Prototypal inheritance

  1. Inheritance, the __proto__
  2. Object.create, Object.getPrototypeOf
  3. The prototype
  4. Crossbrowser Object.create(proto)
  5. hasOwnProperty
  6. Looping with/without inherited properties
  7. Summary

In most languages, there are classes and objects. Classes inherit from other classes.

In JavaScript, the inheritance is prototype-based. That means that there are no classes. Instead, an object inherits from another object Smile

Inheritance, the __proto__

When an object rabbit inherits from another object animal, in JavaScript that means that there is a special property rabbit.__proto__ = animal.

When a rabbit property is accessed, and the interpreter can’t find it in rabbit, it follows the __proto__ link and searches in animal.

The examples using __proto__ work only in Chrome/Firefox. That’s for sheer simplicity. Later we’ll go crossbrowser.

var animal = { eats: true }
var rabbit = { jumps: true }

rabbit.__proto__ = animal  // inherit

alert(rabbit.eats) // true

The eats property is actually taken from animal. Here’s the picture:

If the property is found in rabbit, then __proto__ is not checked.

For example, when eats is in the child object, parent is ignored:

var animal = { eats: true }
var fedUpRabbit = { eats: false}

fedUpRabbit.__proto__ = animal  

alert(fedUpRabbit.eats) // false

One could put a method into animal and it becomes available in rabbit:

var animal = {
  eat: function() { 
    alert( "I'm full" )
    this.full = true
  }
}

var rabbit = { 
  jump: function() { /* something */ }
}

rabbit.__proto__ = animal  

*!*
rabbit.eat()  
*/!*

The rabbit.eat() is executed in two steps:

  1. First, the interpreter looks up rabbit.eat. There’s no eat in rabbit object, so it goes to rabbit.__proto__ and finds it there.

  2. The function runs with this = rabbit.

    The value of this is completely irrelevant to __proto__. It is set exactly to the object before the dot (see more about this here).

    So, this.full = true stores the value in the rabbit object:

Look what we’ve got. An object calls parent method, but this is set to the object itself. That’s the inheritance.

The object, referenced by __proto__ is called a prototype. So, animal is a prototype of rabbit.

Reading looks up, writing doesn't

When a property is read, like this.prop, the interpreter looks it in the prototype.

When a property is assigned, like this.prop = value, then there is no reason to search. The property is written directly into the object (here this).

Same with delete obj.prop. It only deletes the property on object itself, and leave it intact if it is in the prototype.

__proto__ in the spec

If you’ll be reading the specification, what we call __proto__ here is named [[Prototype]] there. And yes, double square brackets are important, because there’s another property named prototype.

Object.create, Object.getPrototypeOf

The __proto__ is a non-standard property, provided by Firefox/Chrome. In other browsers the property still exists internally, but it is hidden.

All modern browsers except Opera (IE from 9) support two standard methods for working with prototypes:

Object.create(proto[, props])
Creates an empty object with given __proto__:

var animal = { eats: true }

rabbit = Object.create(animal)

alert(rabbit.eats) // true

The code above creates empty rabbit with animal __proto__:

Once the rabbit is created, we can add properties to it.

var animal = { eats: true }

rabbit = Object.create(animal)
rabbit.jumps = true

There second argument props is optional and allows to set properties of the new object. Here we skip it, because we are concerned about the inheritance part.

Object.getPrototypeOf(obj)
Returns the value of obj.__proto__. The method is standard, so it works in browsers which don’t support __proto__ property:

var animal = { 
  eats: true
}

rabbit = Object.create(animal)

alert( Object.getPrototypeOf(rabbit) === animal ) // true

So, most modern browsers allow to read the value of __proto__, but not to modify it.

The prototype

There is a good and crossbrowser way of setting __proto__. It requires the use of constructor functions.

Remember, any function creates an object when called with new. Here’s a simple Rabbit constructor to start with:

function Rabbit(name) { 
  this.name = name
}

var rabbit = new Rabbit('John')

alert(rabbit.name) // John

A new function call sets the __proto__ of the object to the value of its prototype property.

Let’s see how it works. For example, let’s make new Rabbit objects which inherits from animal:

var animal = { eats: true }

function Rabbit(name) { 
  this.name = name
}

Rabbit.prototype = animal 

var rabbit = new Rabbit('John')

alert( rabbit.eats ) // true, because rabbit.__proto__ == animal

The code Rabbit.prototype = animal literally means the following:
”set __proto__ = animal for all objects created by new Rabbit.

What is the result of the code? Why?

function Rabbit(name) {
  this.name = name
}

var john = new Rabbit('John')

var animal = { eats: true }
Rabbit.prototype = animal

alert(john.eats)

Open solution
Solution

The result is undefined, because the prototype property is set after the new Rabbit.

As a consequence, john doesn’t have animal prototype, and hence there’s no eats property.

Changing the prototype has no effect on already-created objects.

Crossbrowser Object.create(proto)

The functionality of Object.create(proto) is great, because it allows to inherit directly from the given object. It can be emulated by our own method which works in all browsers.

Here’s the function:

function inherit(proto) {
  function F() {}
  F.prototype = proto
  return new F
}

The result of inherit(animal) is identical to Object.create(animal): an new empty object, with object.__proto__ = animal.

For example:

var animal = { eats: true }

var rabbit = inherit(animal)
 
alert(rabbit.eats) // true
alert(rabbit.hasOwnProperty('eats')) // false, from prototype

Let’s go into details how it works. There are just three lines:

function inherit(proto) {
  function F() {}     // (1)
  F.prototype = proto // (2)
  return new F()      // (3)
}

  1. A new function F is created. The function doesn’t set anything to this, so new F creates an empty object.
  2. F.prototype is set to given proto
  3. The result of new F is an empty object with __proto__ set to the value of F.prototype, which is proto.
  4. Bingo! We’ve got an empty object with given proto.

The function is widely used in libraries and frameworks.

Your function receives an object with options.

/* options contains menu settings: width, height etc */
function Menu(options) {
  // ...
}

You want to “fix” certain options:

function Menu(options) {
  options.width = options.width || 300 // set default value
  // ...
}

… But changing the argument may have bad consequences, because options may be reused in external code.

One way to workaround is to clone options by copying all properties into a new object, and modify it there. This implies certain overhead.

How to solve this problem effectively using inheritance?

P.S. Options can be modified/added, but never removed.

Open solution
Solution

You can inherit from options and modify/add options in the child object:

function inherit(proto) {
  function F() {}
  F.prototype = proto
  return new F
}

function Menu(options) {
  var opts = inherit(options)
  opts.width = opts.width || 300
  // ...
}

All changes will be reflected in the child object only. When Menu finishes, the external code can continue with unmodified options.

The P.S. about deletion is important here, because delete opts.width doesn’t do anything if width is in prototype.

hasOwnProperty

All objects have hasOwnProperty method which allows to check if a property belongs to the object or its prototype.

For example:

function Rabbit(name) {
  this.name = name
}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

alert( rabbit.hasOwnProperty('eats') ) // false, in prototype

alert( rabbit.hasOwnProperty('name') ) // true, in object

Looping with/without inherited properties

A for..in loop outputs all properties from the object and its prototype:

function Rabbit(name) {
  this.name = name
}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

for(var p in rabbit) {
  alert (p + " = " + rabbit[p]) // outputs both "name" and "eats"
}

To get a list of properties, which are not in prototype, filter them through hasOwnProperty:

function Rabbit(name) {
  this.name = name
}

Rabbit.prototype = { eats: true }

var rabbit = new Rabbit('John')

for(var p in rabbit) {
*!*
  if (!rabbit.hasOwnProperty(p)) continue // filter out "eats"
*/!*
  alert (p + " = " + rabbit[p]) // outputs only "name"
}

Summary

The inheritance is implemented through a special property __proto__ (named [[Prototype]] in the specification).

  • When a property is accessed, and the interpreter can’t find it in the object, it follows the __proto__ link and searches it there.
  • The value of this for function properties is set to the object, not its prototype.
  • Assignment obj.prop = val and deletion delete obj.prop

Managing __proto__:

  • Firefox/Chrome give direct access to obj.__proto__. Most recent browsers support read-only access with Object.getPrototypeOf(obj).
  • An empty object with given prototype can be created by Object.create(proto) in most modern browsers, or the following function in all browsers:

    function inherit(proto) {
      function F() {}
      F.prototype = proto
      return new F
    }
    

  • A constructor function sets __proto__ for objects it creates to the value of its prototype property.

Additional methods:

  • for..in loop lists properties in the object and its prototype chain.
  • obj.hasOwnProperty(prop) returns true only if the prop belongs to obj, not its prototype.

Tutorial

Donate

Donate to this project