Basicamente, criamos uma classe em Javascript assim:
const Pessoa = function() {
// Se houvesse herança de uma classe com o nome Humano, ela seria assim, também serve pra chamar métodos da classe pai:
// Humano.call(this);
this.nome = "";
this.telefone = "";
this.cpf = "";
this.mostrar = function() {
alert("Nome: " + this.nome + "\nTelefone: " + this.telefone + "\nCPF: " + this.cpf);
};
};
No caso acima, todo método ou atributo com this
(que é substituído pelo objeto) é público, para simular privados seria algo como var nome = ""
.
Note que não existia a palavra class para criar classes, por isso é usado uma função anônima para isso. As funções também são utilizadas com uma função anônima.
Dessa forma basta criar os objetos assim:
var c = new Pessoa(); // Criação do objeto
// Atributos do objeto:
c.nome = "Carlos";
c.telefone = "1234-5678";
c.cpf = "123.456.789-01";
// Invocação do método:
c.mostrar();
Também podemos criar objetos atribuindo diretamente à variável ou constante, dessa forma:
var c = {
nome: "Carlos",
telefone: "1234-5678",
cpf: "123.456.789-01",
mostrar: function() {
alert("Nome: " + this.nome + "\nTelefone: " + this.telefone + "\nCPF: " + this.cpf);
}
};
c.mostrar();
Ou criando uma nova instância de Object (objeto padrão do Javascript) e adicionando os atributos e métodos, assim:
var c = new Object();
c.nome = "Carlos";
c.telefone = "1234-5678";
c.cpf = "123.456.789-01";
c.mostrar = function() {
alert("Nome: " + this.nome + "\nTelefone: " + this.telefone + "\nCPF: " + this.cpf);
};
c.mostrar();
No entanto, atualmente podemos criar classes em Javascript, o código reescrito ficaria assim:
class Pessoa {
constructor() {
this.nome = "";
this.telefone = "";
this.cpf = "";
}
mostrar() {
alert("Nome: " + this.nome + "\nTelefone: " + this.telefone + "\nCPF: " + this.cpf);
}
};
var c = new Pessoa();
c.nome = "Carlos";
c.telefone = "1234-5678";
c.cpf = "123.456.789-01";
c.mostrar();
Note que agora tivemos que criar um construtor com os atributos, e os métodos não utilizam "function" no começo.
PS: Para pegar o nome da classe, use this.constructor.name
.
Quando criamos uma classe, temos mais trabalho para fazê-la, mas depois que ela está pronta, podemos criar quantos objetos precisarmos vindos dessa mesma classe, e o programa principal fica mais simples, menor e mais natural. Os objetos criados dessa mesma classe são independentes entre si e o status de um não interfere no outro. Essa é uma das vantagens da orientação a objetos.
Podemos também criar construtores nas classes, dessa forma:
class Pessoa {
constructor(nome, telefone, cpf) {
this.nome = nome;
this.telefone = telefone;
this.cpf = cpf;
}
mostrar() {
alert("Nome: " + this.nome + "\nTelefone: " + this.telefone + "\nCPF: " + this.cpf);
}
};
O this é o atributo da classe, e o que está a direita, o parâmetro do construtor.
Aí, desse modo, temos que passar os parâmetros na criação do objeto:
var c = new Pessoa("Carlos", "1234-5678", "123.456.789-01");
c.mostrar();
PS: Podemos também destruir os objetos usando delete, assim:
var c = new Pessoa("Carlos", "1234-5678", "123.456.789-01");
c.mostrar();
delete c;
PS: Caso num construtor precise inicializa um atributo como nulo, use null
.
Também podemos usar métodos estáticos de classes em Javascript, sendo que nesse caso é atributo da classe, por exemplo:
class Veiculo {
static verifCombustivel() {
alert("O combustível do veículo é gasolina!");
}
};
E para chamar, podemos chamar diretamente pela classe, sem criar um objeto, por exemplo:
Veiculo.verifCombustivel();
No entanto, não é possível criar atributos estáticos diretamente, apenas simulá-los, por exemplo:
class Veiculo {
static verifCombustivel() {
alert("O combustível do veículo é " + Veiculo.combustivel + "!");
}
};
Veiculo.combustivel = "gasolina";
Veiculo.verifCombustivel();
PS: Métodos estáticos só podem trabalhar outros métodos e atributos quando estes também forem estáticos, e não podem ser sobrepostos. E atributos estáticos é recomendável eles serem inicializados, e nunca se deve utilizar o this neles.
Colocando this nos atributos ou métodos, mostra que ela é pública, para tornar ela privada, coloque um _ antes do nome do atributo, assim:
class Media {
constructor() {
// Atributos públicos:
this.nota1 = 0;
this.nota2 = 0;
// Atributo supostamente privado:
this._med = (this.nota1 + this.nota2) / 2;
}
};
Na prática, não existe o encapsulamento real em Javascript, apenas uma forma de sinalizar quais atributos não devem ser acessados. Na forma antiga, usando functions no lugar das classes, definíamos o que era público com this e o que era privado sem ele e com o var na frente.
PS: Recentemente podemos usar #
ao invés do underline na frente do atributo pra indicar que ele é "privado", mas isso não funciona em todos os navegadores.
Mas podemos criar métodos públicos para acessar essas variáveis "privadas", mesmo se todas as variáveis forem "privadas". Veja o código acima alterado:
class Media {
constructor(n1, n2) {
// Atributos supostamente privados:
this._nota1 = n1;
this._nota2 = n2;
this._med = (this._nota1 + this._nota2) / 2;
}
// Método público que retorna a conta:
get med() {
return this._med;
}
// Método público que muda a média diretamente:
set med(value) {
this._med = value;
}
};
Podemos ver que os métodos getters e setters tem a indicação get e set antes da função.
E na instância:
var a = new Media(10, 5);
alert("A média é " + a.med);
PS: O uso e a a atribuição de métodos getters e setters são iguais às variáveis, pois são considerados propriedades, e não métodos, portanto, usar o setter do método criado ficaria assim:
var a = new Media(10, 5);
a.med = 10;
alert("A média é " + a.med);
Primeiramente, crie uma classe genérica assim:
class Animal {
vivo() {
alert("O Animal está Vivo!");
}
};
Para fazer a herança numa nova classe, usamos o extends
, dessa forma:
class Gato extends Animal {
};
PS: Isso é uma herança pobre, a classe herdeira pode ter novos atributos e métodos.
Dessa forma, podemos chamar o método assim:
var g = new Gato();
g.vivo();
PS: Javascript não permite herança múltipla. E caso use construtores, sempre chame a classe mãe com o método super
dentro do construtor da classe filha, mesmo se não houver parâmetros.
Pegando o mesmo exemplo da classe anterior, podemos sobrepor o método da classe pai na classe filha, assim:
class Gato extends Animal {
vivo() {
alert("O Gato está Vivo!");
super.vivo(); // Chamada do método da classe pai
}
};
E exibir assim:
var g = new Gato();
g.vivo();
No Javascript podemos usar o polimorfismo de sobreposição, mas não o de sobrecarga.
PS: Pode ser necessário chamar o construtor da classe pai com super, caso a classe herdeira tenha parâmetros, mesmo se a classe pai não tiver nenhum.
Na teoria, não existem métodos abstratos em Javascript, mas podemos simulá-los, criando uma exceção de erro nos métodos que queremos implementar, veja a alteração da classe anterior:
class Animal {
// Simulação de método abstrato:
vivo() {
throw new Error("Implementação do método 'vivo' requerida");
}
};
E nas classes filhas que terão que implementar o método, basta fazer a implementação como achar necessário:
class Gato extends Animal {
// Implementação do método:
vivo() {
alert("O Gato está Vivo!");
}
};
Crie uma classe com o nome Eletrodomestico que servirá de base para outras classes:
class Eletrodomestico {
constructor(marca, ligado) {
this._marca = marca;
this._ligado = ligado;
}
usando() {
document.write("Estou utilizando o Eletrodoméstico!");
}
get marca() {
return this._marca;
}
set marca(value) {
this._marca = value;
}
get ligado() {
return this._ligado;
}
set ligado(value) {
this._ligado = value;
}
};
Baseado nessa classe, crie várias classes com eletrodomésticos diversos, fazendo a sobreposição do método funcionando, mas chamando também a função da classe pai, por exemplo:
class Geladeira extends Eletrodomestico {
constructor(marca, ligado) {
// Chamada do construtor da classe pai:
super(marca, ligado);
}
usando() {
super.usando();
document.write(" E é uma geladeira!");
}
};
E na instância:
var gelad = new Geladeira("Brastemp", true);
gelad.usando();
document.write("<br/>O Eletrodoméstico está ligado? " + gelad.ligado);
Tente também colocar o método da classe Eletrodomestico como abstrato e implementar eles nas classes filhas.
Em Javascript, podemos também criar atributos e métodos em classes por protótipos, como por exemplo:
class Comida {
};
Comida.prototype.sabor = "salgado";
Comida.prototype.verifSabor = function() {
document.write("O sabor da comida é " + this.sabor + ".<br/>");
};
Lembrando que todos os objetos criados terão os mesmos valores definidos nos protótipos, por exemplo:
var arroz = new Comida();
var feijao = new Comida();
arroz.verifSabor();
feijao.verifSabor();
PS: Não dá pra usar métodos estáticos como protótipos.