Revision 347887 of Inheritance revisited

  • Revision slug: JavaScript/Guide/Inheritance_Revisited
  • Revision title: Inheritance revisited
  • Revision id: 347887
  • Created:
  • Creator: mua
  • Is current revision? No
  • Comment When the inheritance is set up, you don't want to execute the `A` constructor at that moment (it could have side effects or expect more complicated arguments). All you want is to hook up `A.prototype` into the prototype chain.

Revision Content

See Inheritance and the constructor's prototype for a description of JavaScript inheritance and the constructor's prototype.

Inheritance has always been available in JavaScript, but the examples on this page use some methods introduced in ECMAScript 5. See the different method pages to see if they can be emulated.

Example

B shall inherit from 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(A.prototype, {
  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();

The important parts are:

  • Types are defined in .prototype
  • You use Object.create() to inherit

prototype and Object.getPrototypeOf

JavaScript is a bit confusing for developers coming from Java or C++, as it's all dynamic, all runtime, and it has no classes at all. It's all just instances (objects). Even the "classes" we simulate are just a function object.

You probably already noticed that our function A has a special property called prototype. This special property works with the JavaScript new operator. The reference to the prototype object is copied to the internal [[Prototype]] property of the new instance. For example, when you do var a1 = new A(), JavaScript (after creating the object in memory and before running function A() with this defined to it) sets a1.[[Prototype]] = A.prototype. When you then access properties of the instance, JavaScript first checks whether they exist on that object directly, and if not, it looks in [[Prototype]]. This means that all the stuff you define in prototype is effectively shared by all instances, and you can even later change parts of prototype and have the changes appear in all existing instances, if you wanted to.

If, in the example above, you do var a1 = new A(); var a2 = new A(); then a1.doSomething would actually refer to Object.getPrototypeOf(a1).doSomething, which is the same as the A.prototype.doSomething you defined, i.e. Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething.

In short, prototype is for types, while Object.getPrototypeOf() is the same for instances.

[[Prototype]] is looked at recursively, i.e. a1.doSomething, Object.getPrototypeOf(a1).doSomething, Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething etc., until it's found or Object.getPrototypeOf returns null.

So, when you call

var o = new Foo();

JavaScript actually just does

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

(or something like that) and when you later do

o.someProp;

it checks whether o has a property someProp. If not it checks Object.getPrototypeOf(o).someProp and if that doesn't exist it checks Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp and so on.

{{ autoPreviousNext("JSGChapters") }}

Revision Source

<p>See <a href="/en-US/docs/JavaScript/Guide/Inheritance_and_the_prototype_chain" title="en-US/docs/JavaScript/Guide/Inheritance_constructor_prototype">Inheritance and the constructor's prototype</a> for a description of JavaScript inheritance and the constructor's prototype.</p>
<p>Inheritance has always been available in JavaScript, but the examples on this page use some methods introduced in ECMAScript 5. See the different method pages to see if they can be emulated.</p>
<h2 id="Example" name="Example">Example</h2>
<p><code>B</code> shall inherit from <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(A.prototype, {
  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>The important parts are:</p>
<ul>
  <li>Types are defined in <code>.prototype</code></li>
  <li>You use <code>Object.create()</code> to inherit</li>
</ul>
<h2 id="prototype_and_Object.getPrototypeOf"><code>prototype</code> and Object.getPrototypeOf</h2>
<p>JavaScript is a bit confusing for developers coming from Java or C++, as it's all dynamic, all runtime, and it has no classes at all. It's all just instances (objects). Even the "classes" we simulate are just a function object.</p>
<p>You probably already noticed that our <code>function A</code> has a special property called <code>prototype</code>. This special property works with the JavaScript <code>new </code>operator. The reference to the prototype object is copied to the internal <code>[[Prototype]]</code> property of the new instance. For example, when you do <code>var a1 = new A()</code>, JavaScript (after creating the object in memory and before running function <code>A()</code> with <code>this</code> defined to it) sets <code>a1.[[Prototype]] = A.prototype</code>. When you then access properties of the instance, JavaScript first checks whether they exist on that object directly, and if not, it looks in <code>[[Prototype]]</code>. This means that all the stuff you define in <code>prototype</code> is effectively shared by all instances, and you can even later change parts of <code>prototype</code> and have the changes appear in all existing instances, if you wanted to.</p>
<p>If, in the example above, you do <code>var a1 = new A(); var a2 = new A();</code> then <code>a1.doSomething</code> would actually refer to <code>Object.getPrototypeOf(a1).doSomething</code>, which is the same as the <code>A.prototype.doSomething</code> you defined, i.e. <code>Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething</code>.</p>
<p>In short, <code>prototype</code> is for types, while <code>Object.getPrototypeOf()</code> is the same for instances.</p>
<p><code><span>[[Prototype]]</span></code> is looked at <em>recursively</em>, i.e. <code>a1.doSomething</code>, <code>Object.getPrototypeOf(a1).doSomething</code>, <code>Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething</code> etc., until it's found or <code>Object.getPrototypeOf </code>returns null.</p>
<p>So, when you call</p>
<pre class="brush: js">
var o = new Foo();</pre>
<p>JavaScript actually just does</p>
<pre class="brush: js">
var o = new Object();
o.[[Prototype]] = Foo.prototype;
o.Foo();</pre>
<p>(or something like that) and when you later do</p>
<pre class="brush: js">
o.someProp;</pre>
<p>it checks whether <code>o</code> has a property <code>someProp</code>. If not it checks <code>Object.getPrototypeOf(o).someProp</code> and if that doesn't exist it checks <code>Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp</code> and so on.</p>
<div>
  {{ autoPreviousNext("JSGChapters") }}</div>
Revert to this revision