March 9, 2015 · javascript prototypes

Inheritance and prototype chains in JavaScript

There are a lot of posts on the web about inheritance and prototypes in JS. In my opinion ones of the best comes from MDN.
Wait! This guy really knows the core of JavaScript, read his incredible articles if you want more.

In this post I'll try to show relations between all elements in JavaScript and an Object.prototype object, which are fundamental and parent for all other elements.

There are two global data types in JavaScript: primitives and objects. So, not all in JS are objects. But primitives in some cases can be converted to objects.

Built-in objects list are here

Primitives:

But, this types of data (except null and undefined) is created by object constructors (or wrappers). For example, when we defined something like this:

var word = "Hello!"  

the String() method is executing and new variable with type "string" is created.
And as we know, primitives are immutable, so we can't add properties for string or boolean.
But, how then we may know string length (which are property of foo variable)?

var foo="123"  
console.log(foo.length) //3  

All these because of prototype chain.
Prototype chain - is a language feature that provides delegation based on prototypes, when object has it own properties as well as shared properties which are inherited.

All object in JavaScript has a prototype property.
This property may be a link to another object or be null. The only object which prototype property is null (in normal case) is Object.prototype (more about it bellow)

For better understanding what is prototypes and how chains are creating, lets look at another simple example:

var bar = {}  
// for simplicity we can say that is a link to
var bar = new Object()

This simple operation in detail mean:

These mean, that bar object inherits all methods and properties from Object.prototype object. That's why we can get the result of bar.toString().

To access object prototype we can use __proto__ property which will show actual prototype of object.

Constructor - is a function that create object (more about it below), excellent article about constructors and more is here

So, what is a prototype chain?
In a nutshell, this is how properties are looking-up. When we call some property, for example bar.toString, if this property not found in object - next this property will be checked in object.[[prototype]], next in object.[[prototype]].[[prototype]] and so on. Until property is found or if object.__proto__ returns null. This is mean that prototype chain is ended, and in this case property returns undefined as result.
Let's create a string:

var a = "foo"  
console.log(a.__proto__ === String.prototype) //true  
console.log(String.prototype.__proto__ === Object.prototype) //true  

And create new method in Object.prototype, that all objects can access it:

Object.prototype.ping = function () {  
    return "pong"
}
console.log( a.ping() )                                   //"pong", inherited from Object.prototype  
console.log(a.hasOwnProperty("ping"))                     //false, a doesn't have ping property  
console.log(a.__proto__.hasOwnProperty("ping"))           //false, String.prototype doesn't have ping property  
console.log(a.__proto__.__proto__.hasOwnProperty("ping")) //true, ping property found in Object.protoype  
console.log(a.hasOwnProperty("toString"))                 //false, a doen't have toString property  
console.log(a.__proto__.hasOwnProperty("toString"))       //true, toString property found in String.prototype  
console.log(a.toString === String.prototype.toString)     //true  

Note: Object.prototype also have toString property, but it's two different methods.
But, if primitives can't have properties at all. How we can do that?
This feature is calling autoboxing (or boxing is some cases). To access properties of primitives a temporary object is created, after properties are accessed this object is deleted:

var wrapper = new String("foo")  
console.log( wrapper.ping() )  
delete wrapper  

In "native constructors" block are located constructors that creates corresponding objects in this example. All functions (native and own) are created by Function constructor, and inherits their properties from Function.prototype.

var Foo = function () {}  
//all functions inherits their properties from Function.prototype
console.log(Foo.__proto__      === Function.prototype) //true  
console.log(Function.__proto__ === Function.prototype) //true  
console.log(String.__proto__   === Function.prototype) //true  
console.log(Number.__proto__   === Function.prototype) //true  
console.log(Array.__proto__    === Function.prototype) //true  
console.log(Object.__proto__   === Function.prototype) //true  
//constructors:
console.log(Foo.prototype.constructor      === Foo)     //true  
console.log(Function.prototype.constructor === Function)//true  
console.log(String.prototype.constructor   === String)  //true  
console.log(Number.prototype.constructor   === Number)  //true  
console.log(Array.prototype.constructor    === Array)   //true  
console.log(Object.prototype.constructor   === Object)  //true  

Constructor

Constructor creates object and sets all it properties. For better understanding how it works, take a look on algorithm of function creation from Dmitry Soshnikov

F = new NativeObject();

/* property [[Class]] is "Function" */
F.[[Class]] = "Function"

/* a prototype of a function object */
F.[[Prototype]] = Function.prototype

/* reference to function itself */
/* [[Call]] is activated by call expression F() */
/* and creates a new execution context */
F.[[Сall]] = <reference to function>

/*  built in general constructor of objects */
/*  [[Construct]] is activated via "new" keyword */
/*  and it is the one who allocates memory for new */
/*  objects; then it calls F.[[Call]] */
/*  to initialize created objects passing as */
/*  "this" value newly created object */
F.[[Construct]] = internalConstructor

/*  scope chain of the current context  */
/*  i.e. context which creates function F */
F.[[Scope]] = activeContext.Scope  
/* if this functions is created  */
/* via new Function(...), then */
F.[[Scope]] = globalContext.Scope

/* number of formal parameters */
F.length = countParameters

/* a prototype of created by F objects */
__objectPrototype = new Object();  
__objectPrototype.constructor = F // {DontEnum}, is not enumerable in loops  
F.prototype = __objectPrototype

return F  

How about own constructors?

Object.prototype.ping = function () {  
    return "pong"
}
//simple object constructor
var Foo = function () {  
    this.x = 5
    this.y = "yes"
    this.z = false
    this.check = function () {
        return this.y + ", checked"
        }
}
//create object using it
var a = new Foo()  
console.log(a.check())   //"yes, checked", own  
//another object, set prototype to a object. Now b can access all properties from a
var b = {  
    x: 13,
    z: 19,
    __proto__: a
}
console.log(b.x)                                     //13, own  
console.log(b.z)                                     //19, own  
console.log(b.y)                                     //"yes", delegated from a  
console.log(b.check())                               //"yes, checked", delegated from a  
console.log(b.ping())                                //"pong", delegated from Object.prototype  
console.log(b.ping === Object.prototype.ping)        //true  
console.log(b.toString())                            //"[object Object], delegated from Object.prototype  
console.log(b.toString === Object.prototype.toString)//true  
delete b.x                                           //own property x deleted  
console.log(b.x)                                     //5, delegated from a  
delete a.x                                           //x property from a deleted  
console.log(b.x)                                     //undefined, x property not found in prototype chain  

Sure, modifying native objects is a bad idea. This called monkey-patching and may cause some problems.
But when do this carefully, it may be very useful.

Also, good idea - is to protect own properties from being modified or listed in counters:

Object.defineProperty(String.prototype, "foo", {  
    value: function () {
        return "something"
        },
    writable: true,
    enumerable: true,
    configurable: true
 })
var x = "some text"  
for (key in x) {  
        console.log(x[key])  //some text, [Function]
}
//hide property from being listed in counters and modifying/deleting
Object.defineProperty(String.prototype, "foo", {  
    writable: false,
    enumerable: false,
    configurable: false
})
console.log(x.foo())         //"something"  
delete String.prototype.foo  
console.log(x.foo())         //"something"  
String.prototype.foo = null  
console.log(x.foo())         //"something"  
for (key in x) {  
        console.log(x[key])  //some text
}

//check it:
console.log(Object.getOwnPropertyDescriptor(String.prototype, "foo"))  
/*
{ value: [Function],
  writable: false,
  enumerable: false,
  configurable: false }
*/

That's all for now :)

Refs:
MDN
ECMA-262 by Dmitry Soshnikov
Angus Croll

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket
Comments powered by Disqus