Javascript: Orientação a Objetos – Herança

A programação orientada a objetos possui diversas vantagens, as quais não pretendo entrar em detalhes. Em Javascript existe a possibilidade de se programar orientado a objetos, embora este estilo de programação nesta linguagem seja um pouco diferente, e acabe causando espanto nos iniciantes. Principalmente para quem é acostumado com linguagens como Java, o estilo de código orientado a objetos em Javascript é muitíssimo diferente.

Mas não apenas o estilo, também o comportamento! O que dizer da herança? A herança em Javascript, não é como você está acostumado a ver nas linguagens tradicionais. O que existe, então? O que costuma-se chamar de herança estática, ou seja, uma nova classe filha literalmente copia todos os atributos e métodos da classe pai. Isto trás diversas conseqüências que você tem que ficar bastante atento, pois senão seu código vai se comportar de maneira inesperada.

“Ei, você fala em herança estática, mas como eu faço isso? Cadê o ‘extends’ ?”. Pois é, não existe. Para você aplicar a herança, é necessário um pouco de código, pois não existe uma palavra chave, como extends, que ajude você. Também é necessário entender o significado de “Prototype”. Para isto, vamos lembrar do padrão de projeto Prototype, pois a idéia é semelhante, senão a mesma. Segundo nosso colega José Anízio Pantoja Maia, em seu artigo publicado no GUJ:”O Pattern Prototype tem como objetivo criar objetos específicos a partir da instância de um protótipo. Isso permite criar novos objetos através da cópia deste protótipo.”.

Ele também nos dá um exemplo que ilustra bem a idéia do padrão: “O uso de células representa perfeitamente os objetivos deste pattern. Uma célula dividia em duas se tornam duas células idênticas com as mesmas funcionalidades.”. Então, em Javascript toda classe possui um Protótipo, que representa um “template” das funcionalidades que esta classe possui. Desta forma, você pode criar uma nova classe herdando” o protótipo de outra.

Vamos a um exemplo de uma classe em javascript, criada sem ajuda de bibliotecas:

// Construtor.
function MinhaClasse() {
this.umatributo = "Atributo de MinhaClasse";
}

// Definindo o prototype.
MinhaClasse.prototype = {
umMetodo: function() {
alert("Um Atributo de MinhaClasse: " + this.umatributo);
},

outroMetodo: function() {
}
}

//Instanciando a classe e testando.
var minhaClasse = new MinhaClasse();
minhaClasse.umMetodo();

Reparou alguma semelhança com os “arrays associativos” que comentei em posts anteriores? Pois é, uma classe parece um Array Associativo contendo funções e variáveis, não? E mais uma coisa, esta forma de criar uma classe em Javascript não é a única. Você também poderia fazer:

var MinhaClasse = function() {

// Definindo o construtor.
this.umatributo = "Um Atributo";
};

// Definindo um novo método no prototype.
MihaClasse.prototype.meuMetodo = function() {
alert(this.umatributo);
};

// Instanciando.
var minhaClasse = new MinhaClasse();
minhaClasse.meuMetodo();

E que tal esta?

function MinhaClasse() {
this.umatributo = "Um Atributo";
}

var instancia = new MinhaClasse();
instancia.meuMetodo = function() {
alert(this.umatributo);
}
instancia.meuMetodo();

Opa, existe ainda outra forma:

function MinhaClasse() {
this.umatributo = "Um Atributo";

// Definindo o método umMetodo como sendo a função _umMetodo.
this.umMetodo = _umMetodo;

// Uma função que vai representar o método.
function _umMetodo() {
alert(this.umatributo);
}

}
var instancia = new MinhaClasse();
instancia.umMetodo();

Confuso, não? Eu também acho, e demorei até me acostumar. Sugiro adotar a maneira que mais lhe agrada e sempre usar ela. Eu prefiro a primeira forma, pois agrupa melhor o que pertence a uma classe. Assim sendo, adotarei este estilo daqui em diante. Voltemos ao assunto da herança e o tal do Prototype. Você está atento e observou no primeiro exemplo a passagem …MinhaClasse.prototype = { … }… Pois é, estou definindo o protótipo. E caso eu queira criar uma nova classe e herdar desta MinhaClasse? Vamos lá:

// Construtor.
function MinhaClasse() {
this.umatributo = "Atributo de MinhaClasse";
}

// Definindo os métodos.
MinhaClasse.prototype = {

// Método 1.
umMetodo: function() {
alert("Um Atributo de MinhaClasse: " + this.umatributo);
},

// Método 2.
outroMetodo: function() {
}

}

function MinhaClasseFilha() {
this.umnovoatributo = "novo atributo";
}

MinhaClasseFilha.prototype = new MinhaClasse();
var minhaClasseFilha = new MinhaClasseFilha();
minhaClasseFilha.umMetodo();

Agora você possui o método “umMetodo” na sua classe filha. Agora um grande detalhe, que você deve prestar atenção! Quando você define um método no “protótipo” da classe, todas as instâncias desta definição de classe irão possuir este método! A herança só é possível com protótipos, portanto, cuidado com códigos como este:

// Construtor.
function MinhaClasse() {
this.umatributo = "Atributo de MinhaClasse";
}

MinhaClasse.prototype = {
umMetodo: function() {
alert("Um Atributo de MinhaClasse: " + this.umatributo);
},

outroMetodo: function() {
}

}

// Classe Filha.
function MinhaClasseFilha() {
this.umnovoatributo = "novo atributo";
}

// Herdando o prototype da classe Pai.
MinhaClasseFilha.prototype = new MinhaClasse();
MinhaClasseFilha.metodoTeste = function() {
alert("Método de Teste");
}

// Mais uma Classe.
function MinhaSegundaClasseFilha() {
}

MinhaSegundaClasseFilha.prototype = new MinhaClasseFilha();
var minhaSegundaClasseFilha = new MinhaSegundaClasseFilha();
// Ops, será que esse método existe? Não!
minhaSegundaClasseFilha.metodoTeste();

Percebeu a diferença sutil? O método metodoTeste não foi definido dentro do prototype da classe MinhaClasseFilha, portanto, a classe MinhaSegundaClasseFilha não vai possuir este método. Outro detalhe, não existe sobrecarga de métodos em Javascript, caso você reescreva o método na classe filha, o método da classe pai foi perdido.

Algumas bibliotecas auxiliam na criação de objetos, como a Prototype, que já comentei anteriormente. Em um próximo artigo, vou explicar melhor a utilização dela. E por último, alguém me ajuda a escolher um tema definitivo para o blog! Eta indecisão! 🙂

×