mozilla

Revision 315355 of Herança Revisitada

  • Revision slug: JavaScript/Guide/Inheritance_Revisited
  • Revision title: Herança Revisitada
  • Revision id: 315355
  • Created:
  • Creator: galvao
  • Is current revision? No
  • Comment

Revision Content

Veja Herança e o protótipo de construtor para uma descrição de Herança Javascript e o protótipo de construtor.

Herança sempre esteve disponível em JavaScript, mas os exemplos desta página usam alguns métodos introduzidos em ECMAScript 5. Veja as diferentes páginas de método para ver se eles podem ser emulados.

Exemplo

B deve herdar de A:

function A(a){
  this.varA = a;
}
A.prototype = {
  varA : null,
  doSomething : function(){
    // ...
  }
}
function B(a, b){
  A.call(this, a);
  this.varB = b;
}
B.prototype = Object.create(new A(), {
  varB : { value: null, enumerable: true, configurable: true, writable: true },
  doSomething : { value: function(){ // override
       A.prototype.doSomething.apply(this, arguments); // call super
       // ...
    }, enumerable: true, configurable: true, writable: true }
})

var b = new B();
b.doSomething();

As partes importantes são:

  • Tipos são definidos em .prototype
  • Você usa Object.create() para herdar

prototype e Object.getPrototypeOf

JavaScript é um pouco confuso para desenvolvedores vindos de Java e C++, já que é toda dinâmica, toda tempo de execução e não possui classes de forma alguma. Até as "classes" que simulamos são apenas um objeto de função.

Você provavelmente já percebeu que a nossa function A tem uma propriedade especial chamada prototype. Essa propriedade especial funciona com o operador JavaScript new. A referência para o objeto protótipo é copiada para a propriedade interna [[Prototype]] da nova instância. Por exemplo, quando você faz var a1 = new A(), JavaScript (depois de criar o objeto em memória e antes de executar function A() com this definida para ela) define a1.[[Prototype]] = A.prototype. Quando você então acessa propriedades da instância, JavaScript primeiro verifica se elas existem naquele objeto diretamente, e se não, procura em [[Prototype]]. Isso significa que tudo o que você define em prototype é efetivamente compartilhado por todas as instâncias, e você pode até mudar partes de prototype depois e ter estas mudanças aparecendo em todas as instâncias existentes, se você quiser.

Se, no exemplo acima, você fizer var a1 = new A(); var a2 = new A(); então a1.doSomething na verdade se referirira a Object.getPrototypeOf(a1).doSomething, que é o mesmo que o A.prototype.doSomething que você definiu, ou seja Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething.

Resumindo, prototype é para tipos, enquanto que Object.getPrototypeOf() é a mesma coisa para instâncias.

[[Prototype]] é procurado recursivamente, ou seja a1.doSomething, Object.getPrototypeOf(a1).doSomething, Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething etc., até ser encontrado ou Object.getPrototypeOf retorna null.

Então quando você chama

var o = new Foo();

JavaScript na verdade faz apenas

var o = new Object();
o.[[Prototype]] = Foo.prototype;
o.Foo();

(ou algo parecido) e quando mais tarde você faz 

o.someProp;

verifica se o possui a propriedade someProp. Em caso negativo verifica Object.getPrototypeOf(o).someProp  e se isso não existir verifica  Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp e assim por diante.

{{ autoPreviousNext("JSGChapters") }}

Revision Source

<p>Veja <a href="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Inheritance_and_the_prototype_chain" title="https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Inheritance_and_the_prototype_chain">Herança e o protótipo de construtor</a> para uma descrição de Herança Javascript e o protótipo de construtor.</p>
<p>Herança sempre esteve disponível em JavaScript, mas os exemplos desta página usam alguns métodos introduzidos em ECMAScript 5. Veja as diferentes páginas de método para ver se eles podem ser emulados.</p>
<h2 id="Example" name="Example">Exemplo</h2>
<p><code>B</code> deve herdar de <code>A</code>:</p>
<pre class="brush: js">
function A(a){
  this.varA = a;
}
A.prototype = {
  varA : null,
  doSomething : function(){
    // ...
  }
}
function B(a, b){
  A.call(this, a);
  this.varB = b;
}
B.prototype = Object.create(new A(), {
  varB : { value: null, enumerable: true, configurable: true, writable: true },
  doSomething : { value: function(){ // override
       A.prototype.doSomething.apply(this, arguments); // call super
       // ...
    }, enumerable: true, configurable: true, writable: true }
})

var b = new B();
b.doSomething();
</pre>
<p>As partes importantes são:</p>
<ul>
  <li>Tipos são definidos em <code>.prototype</code></li>
  <li>Você usa <code>Object.create()</code> para herdar</li>
</ul>
<h2 id="prototype_e_Object.getPrototypeOf"><code>prototype</code> e Object.getPrototypeOf</h2>
<p>JavaScript é um pouco confuso para desenvolvedores vindos de Java e C++, já que é toda dinâmica, toda tempo de execução e não possui classes de forma alguma. Até as "classes" que simulamos são apenas um objeto de função.</p>
<p>Você provavelmente já percebeu que a nossa <code>function A</code>&nbsp;tem uma propriedade especial chamada <code>prototype</code>. Essa propriedade especial funciona com o operador JavaScript <code>new</code>. A referência para o objeto protótipo é copiada para a propriedade interna <code>[[Prototype]]</code>&nbsp;da nova instância. Por exemplo, quando você faz <code>var a1 = new A()</code>, JavaScript (depois de criar o objeto em memória e antes de executar function <code>A()</code> com&nbsp;<code>this</code> definida para ela) define&nbsp;<code>a1.[[Prototype]] = A.prototype</code>. Quando você então acessa propriedades da instância, JavaScript primeiro verifica se elas existem naquele objeto diretamente, e se não, procura em <code>[[Prototype]]</code>. Isso significa que tudo o que você define em <code>prototype</code>&nbsp;é efetivamente compartilhado por todas as instâncias, e você pode até mudar partes de <code>prototype</code>&nbsp;depois e ter estas mudanças aparecendo em todas as instâncias existentes, se você quiser.</p>
<p>Se, no exemplo acima, você fizer <code>var a1 = new A(); var a2 = new A();</code> então&nbsp;<code>a1.doSomething</code>&nbsp;na verdade se referirira a <code>Object.getPrototypeOf(a1).doSomething</code>, que é o mesmo que o&nbsp;<code>A.prototype.doSomething</code> que você definiu, ou seja&nbsp;<code>Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething</code>.</p>
<p>Resumindo, <code>prototype</code> é para tipos, enquanto que&nbsp;<code>Object.getPrototypeOf()</code> é a mesma coisa para instâncias.</p>
<p><code><span>[[Prototype]]</span></code> é procurado&nbsp;<em>recursivamente</em>, ou seja&nbsp;<code>a1.doSomething</code>, <code>Object.getPrototypeOf(a1).doSomething</code>, <code>Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething</code> etc., até ser encontrado ou&nbsp;<code>Object.getPrototypeOf </code>retorna null.</p>
<p>Então quando você chama</p>
<pre class="brush: js">
var o = new Foo();</pre>
<p>JavaScript na verdade faz apenas</p>
<pre class="brush: js">
var o = new Object();
o.[[Prototype]] = Foo.prototype;
o.Foo();</pre>
<p>(ou algo parecido) e quando mais tarde você faz&nbsp;</p>
<pre class="brush: js">
o.someProp;</pre>
<p>verifica se&nbsp;<code>o</code> possui a propriedade&nbsp;<code>someProp</code>. Em caso negativo verifica&nbsp;<code>Object.getPrototypeOf(o).someProp</code>&nbsp; e se isso não existir verifica &nbsp;<code>Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp</code> e assim por diante.</p>
<div>
  {{ autoPreviousNext("JSGChapters") }}</div>
Revert to this revision