Herança é capacidade de um objeto reusar (herdar) os métodos e propriedades de outro objeto. O modelo de orientação a objetos baseado em protótipos, estabelece que um objeto serve de “molde” ou “base” (protótipo) para outro e a linguagem javascript adiciona a propriedade global “instanceof” para definir se um objeto “é” do mesmo tipo do objeto base (protótipo). Para implementar a herança, voce define um objeto base (protótipo) que fornecerá as características aos outros objetos.
Todos os objetos definidos pelo desenvolvedor são candidatos a objeto base. Como medida de segurança as classes Native e Host não estão eleitos a servirem como objetos base.
Selecionado o objeto base, agora voce pode criar os objetos que herdarão e modificarão o objeto base conforme os requisitos. Os objetos filhos criados pelo desenvolvedor herdam todas as propriedades e métodos do objeto base, incluindo o construtor e as implementações de métodos. Lembrando que todas as propriedades e métodos são públicos, então os objetos podem acessá-los diretamente. Esses objetos podem adicionar novas propriedades e métodos não presentes no objeto base ou reescrever com novas implementações.
Keyword This
A palavra chave This faz referência ao escopo do objeto onde ela está sendo chamada.
Como o uso do This no ECMAScript existe a possibilidade de emular os escopos privados usando a palavra chave var, já que por default a linguagem só conhece o escopo público.
function objetoY() { var variavel_privada = "Essa variável é privada"; this.variavel_publica = "Essa variável é pública"; }
Nesse código a variável denominada “variavel_privada” não é propriedade do objeto “objetoY” e sim uma propriedade local ao contexto desse objeto, simulando assim uma variável privada já que outros contextos não terão acesso a ela, apenas métodos e propriedades internas ao objeto, enquanto a propriedade “variavel_publica” faz parte do objeto e é de escopo público.
Herança via Object masquerading
É uma estratégia que emula a herança, um construtor associa todas as propriedades e métodos (com o paradigma de declaração de Construtor) usando a keyword “this” para o contexto interno do qual foi referenciado. Porque o construtor é como uma função, voce pode montar o construtor de um objeto “A” dentro de um método de um objeto “B” e chamá-lo. O objeto “B” então recebe as propriedades e métodos definidos no construtor de “A” porque o this agora aponta para o contexto do novo objeto.
Cria o objeto que servirá de base:
function A(sColor) { this.color = sColor; this.sayColor = function () { alert(this.color); }; }
Agora eu crio o objeto chamado de “B” que herdará de “A”, quando eu chamo o objeto “A”, ele é referenciado ao contexto interno e o “this” passa a pertencer a “B”:
function B(sColor, sName) { this.newMethod = A; this.newMethod(sColor); delete this.newMethod; this.name = sName; this.sayName = function () { alert(this.name); }; }
Ao executar essas sentenças:
var objA = new ClassA('red'); var objB = new ClassB('blue', 'Nicholas'); objA.sayColor(); //outputs 'red' objB.sayColor(); //outputs 'blue' objB.sayName(); //outputs 'Nicholas' alert(objB instanceof A ); //false alert(objB instanceof B ); //true
Temos as mesmas chamadas de A em B com emulação completa da herança.
Como perceberam, Object Masquerading suporta a implementação de múltipla herança, mas como se trata de uma estratégia de emulação, essa abordagem não define o tipo do objeto que herda semelhante aos tipos herdados e portanto falha ao tentar comparar pelo “instanceof“.
Herança via métodos call() e apply()
Os métodos globais call e apply (que todo objeto herda do objeto Global) são estratégias semelhantes ao “Object Masquerading” e importam o contexto de um objeto ao outro.
call(Objeto, argumento1, argumento2, ...) apply(Objeto, array-de-argumentos)
Se diferenciam somente no quesito que se refere aos parâmetros passados, onde o método call recebe uma sequencia de parâmetros, enquanto o método apply recebe um array de parâmetros.
function nome(sPrefixo, sSufixo) { alert(sPrefixo + this.parametro_interno + sSufixo); }; var obj = new Object(); obj.parametro_interno = 'Milfont'; nome.call(obj, 'O ', ' é o mais elegante. ');
Observe que nesse exemplo a função “nome” está definida fora do objeto “obj” e associa a propriedade parametro_interno a seu próprio contexto, utilizamos o método call para passar o objeto “obj” ao contexto da função “nome” e a sequência de parâmetros esperados pelo seu construtor.
A função apply se comporta da mesma maneira e difere apenas na execução:
nome.apply(obj, new Array('O ', ' é o mais elegante. '));
Ao invés de passar os parâmetros em sequência, passamos um array com a sequência desses parâmetros.
A vantagem do método apply é que toda função tem uma propriedade chamada arguments que herda do objeto Global e facilita a implementação:
function A(sNome) { this.nome = sNome; this.digaNome = function () { alert(this.nome); }; } function B(sNome, sName) { A.apply(this, arguments); this.sobrenome = sName; this.digaSobrenome = function () { alert(this.sobrenome); }; }
Aqui temos dentro da função “B” a chamada de “A” passando pelo método apply o contexto de “B” para o interior da função “A”, observe que repassa a propriedade arguments que é um array de argumentos recebidos.
Executando, teríamos:
var objA = new A('martins'); var objB = new B('Christiano', 'milfont'); objA.digaNome(); // 'martins' objB.digaNome(); // 'Christiano' objB.digaSobrenome(); // 'milfont'
Herança via Prototype
A forma de herança atualmente reconhecida pela especificação é a cadeia de protótipos ou Prototype chaining. Utilizando a propriedade prototype que todos os objetos herdam de Global, voce associa o contexto (métodos e propriedades) a outro objeto e o qualifica a ser do mesmo tipo do objeto que ele está recebendo.
function A() {} A.prototype.nome = 'red'; A.prototype.digaNome = function () { alert(this.nome); }; function B() {} B.prototype = new A();
Aqui a função B recebe todos os métodos e propriedades de A e passa a ser do tipo dela, executando teríamos:
var objA = new A(); var objB = new B(); objA.nome = 'martins'; objB.nome = 'Christiano'; objA.digaNome(); // martins objB.digaNome(); // Christiano alert(objB instanceof A); // true alert(objB instanceof B); // true
Formas híbridas podem ser usadas, mesclando esses métodos na construção dos objetos.
Multipla herança
Algumas linguagens orientadas a objetos habilitam o suporte à múltipla herança. Que é a capacidade de um objeto herdar as propriedades (métodos e atributos) de mais de um objeto. Além que esse objeto passa a ser da espécie dos objetos que ele herda, como por exemplo:
function Passaro(){ this.nome = 'papagaio'; } function Produto(){ this.valor = 'R$10,00'; } Passaro.prototype = new Produto; Passaro.prototype.imprimir = function(){ return this.valor + ' - ' + this.nome; }
Uma classe PetStore poderia realizar um teste se o periquito é dos tipos Produto e Passaro para aplicar medicamento adequado à espécie por exemplo, esse tipo de construção é comum em linguagens como C, é simulado em Java por meio de interfaces.
var passaro = new Passaro(); alert(passaro instanceof (Produto)); // saida: true alert(passaro instanceof (Passaro)); // saida: true alert(passaro.imprimir()); // saida: "R$10,00 - papagaio"
Javascript não suporta múltipla herança pelo método de prototype que é o método que define o tipo do objeto, existe entretanto como contornar isso, um exemplo é a biblioteca zInherit (http://www.nczonline.net/downloads/) de Nicholas C. Zakas (http://www.nczonline.net/writing/), autor dos excelentes livros “Professional Ajax” e “Professional JavaScript for Web Developers”.
Esse script acrescenta os métodos inheritFrom e instanceOf ao objeto nativo Object.
function Biologia(){ this.reino = 'animal'; } function Produto(){ this.valor = 'R$10,00'; } function Passaro(){ Produto.apply(this); Biologia.apply(this); this.nome = 'periquito'; } Passaro.prototype.inheritFrom(Produto); Passaro.prototype.inheritFrom(Biologia); Passaro.prototype.imprimir = function(){ return this.reino + ' - ' + this.valor + ' - ' + this.nome; } var passaro = new Passaro(); alert(passaro.instanceOf(Produto)); //saida : true alert(passaro.instanceOf(Biologia)); //saida : true alert(passaro instanceof (Passaro)); //saida : true alert(passaro.imprimir()); // saida: "animal - R$10,00 - papagaio"
O metodo apply() habilita a aplicar um método de outro objeto no contexto de um objeto diferente.
Os frameworks modernos como ExtJS e YUI tem suas formas de implementarem a múltipla herança. Uma das formas mais utilizadas pelos Frameworks Ajax é copiarem os métodos e variáveis de um protótipo ao objeto que herdará.
Posted in JavaScript, Linguagens, Orientação a Objetos, Web Development ~ 4 Comments

