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:
Object
is a constructor function.proto
is different—it is an instance ofObject()
, notObject
itself.The ancestral links between prototypes and their children is called the prototype chain.
Human example:
Grandparent \ Parent \ Child
JavaScript example:
Object \ String \ myString
When 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's
constructor
property (foo.constructor
) is notfoo's
own property. It is the property offoo's
parent,Object
(foo.__proto__
).var foo = {}; foo.constructor === foo.__proto__.constructor; // true
NOTE: An identifier resolution takes place when calling
foo.constructor
andfoo.__proto__.constructor
. Both expressions find the sameconstructor
property within the prototype chain, and it happens to be theconstructor
property offoo's
parent.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 thecontructor
property ofObject's
prototype.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__ property
The chain would look something like:
null // foo.__proto__.__proto__ \ Object // foo.__proto__ \ foo // foo
Here is a similar example using a
String
object.var str = new String(); str.constructor === str.__proto__.constructor; // [1] true str.constructor === str.__proto__.__proto__.constructor; // [2] false
[1]
shows thatstr's
constructor
property is not its own property, but is the property of its parent,String
. Unlike previous example, no error is thrown at[2]
sincestr's
grandparent has aconstructor
property. Notice, however, that theconstructor
property ofstr's
grandparent is different from that ofstr's
parent.Consider the following:
var foo = {}, str = new String(); foo.__proto__.constructor === str.__proto__.__proto__.constructor; // true
The expression above shows that the
constructor
property offoo's
parent is the sameconstructor
property ofstr's
grandparent. This is becauseObject
is both the parent offoo
and the grandparent ofstr
.foo.__proto__; // Object { ... } str.__proto__.__proto__; // Object { ... } foo.__proto__ === str.__proto__.__proto__; // true
Here is the prototype chain for a
String
object.var str = new String(); str.__proto__; // String { ... } str.__proto__.__proto__; // Object { ... } str.__proto__.__proto__.__proto__; // null
The chain would look something like:
null // str.__proto__.__proto__.__proto__ \ Object // str.__proto__.__proto__ \ String // str.__proto__ \ str // str