Inheritance
Every object has a
__proto__property whose value is its parent object.var foo = {}; foo.__proto__; // Object { ... } foo.prototype; // undefined var proto = foo.__proto__; typeof proto; // "object" typeof Object; // "function" proto === Object; // false - object ≠ function foo instanceof Object; // true proto instanceof Object; // false ?NOTE:
Objectis a constructor function.protois different—it is an instance ofObject(), notObjectitself.The ancestral links between prototypes and their children is called the prototype chain.
Human example:
Grandparent \ Parent \ ChildJavaScript example:
Object \ String \ myStringWhen an object's property is referenced, an property lookup takes place. During this process, JavaScript looks at all the object's own properties, and if the property is found, it is returned. However, if the property cannot be found, JavaScript will go to the object's prototype (or parent) and look there. If the property still cannot be found, JavaScript will look at the prototype's parent, and so on. JavaScript will continue this search until it reaches the end of the prototype chain, and if the property cannot be found by the end of the lookup, JavaScript will return the value
undefined.Fun with
__proto__foo'sconstructorproperty (foo.constructor) is notfoo'sown property. It is the property offoo'sparent,Object(foo.__proto__).var foo = {}; foo.constructor === foo.__proto__.constructor; // trueNOTE: An identifier resolution takes place when calling
foo.constructorandfoo.__proto__.constructor. Both expressions find the sameconstructorproperty within the prototype chain, and it happens to be theconstructorproperty offoo'sparent.foo's"grandparent" isnull, and therefore, does not have a constructor.var foo = {}; foo.constructor === foo.__proto__.__proto__.constructor; // [1] error /* Footnotes: [1] Uncaught TypeError: Cannot read property 'constructor' of null */Recall that
foo's__proto__isObject, andObject's__proto__isnull. This is why we get an error when trying to access thecontructorproperty ofObject'sprototype.Here is the prototype chain for
foo.var foo = {}; foo.__proto__; // Object { ... } foo.__proto__.__proto__; // null foo.__proto__.__proto__.__proto__; // error - null does not have a __proto__ propertyThe chain would look something like:
null // foo.__proto__.__proto__ \ Object // foo.__proto__ \ foo // fooHere is a similar example using a
Stringobject.var str = new String(); str.constructor === str.__proto__.constructor; // [1] true str.constructor === str.__proto__.__proto__.constructor; // [2] false[1]shows thatstr'sconstructorproperty is not its own property, but is the property of its parent,String. Unlike previous example, no error is thrown at[2]sincestr'sgrandparent has aconstructorproperty. Notice, however, that theconstructorproperty ofstr'sgrandparent is different from that ofstr'sparent.Consider the following:
var foo = {}, str = new String(); foo.__proto__.constructor === str.__proto__.__proto__.constructor; // trueThe expression above shows that the
constructorproperty offoo'sparent is the sameconstructorproperty ofstr'sgrandparent. This is becauseObjectis both the parent offooand the grandparent ofstr.foo.__proto__; // Object { ... } str.__proto__.__proto__; // Object { ... } foo.__proto__ === str.__proto__.__proto__; // trueHere is the prototype chain for a
Stringobject.var str = new String(); str.__proto__; // String { ... } str.__proto__.__proto__; // Object { ... } str.__proto__.__proto__.__proto__; // nullThe chain would look something like:
null // str.__proto__.__proto__.__proto__ \ Object // str.__proto__.__proto__ \ String // str.__proto__ \ str // str