JavaScript原型链

prototype,proto和constructor

prototype是一个函数对象的属性,它是所有由该函数作为构造器创建的对象的原型。

__proto__是所有对象的属性,该属性指向自身的原型对象。

此外还有一个constructor对象,该对象是所有prototype对象的属性,指向函数对象本身。

他们的关系确实很绕,笔者一直觉得如果prototype这个属性名换一个名称,会让初学者好理解很多(虽然从意思上来讲prototype确实是对的),因此prototype时而表意,时而表属性,讲的人很容易把听的人绕晕。

示例

这里再强调一下,只有函数对象有prototype属性,但是所有对象都有__proto__属性,我们所说的原型链中维护原型关系的属性是__proto__属性。

再看上面这张图,函数对象本身的prototype都指向了函数.prototype对象,这个很好理解,如Object的prototype肯定是Object.prototype,Foo的prototype肯定是Foo.prototype。另外之前说过,函数对象的prototype的constructor属性指向的是函数本身,这个也很好理解,从图中可以看出,Object.prototype的constructor指向了Object,Foo.prototype的constructor指向了Foo。这样第二列和第三列中间的小环就有了。

接下来我们来看,函数对象本身都是有Function创建的,之前说过,由构造器创建的对象的__proto__指向该构造器的prototype对象,所以很明显,最左一列各自的\proto都指向了各自的构造器的prototype;也基于同样理由,所有函数的__proto__都应该指向Function.prototype。

最后,所有函数对象的prototype的__proto__一般指向Object.prototype,除非出于继承需要,我们手动更改过。Object.prototype的__proto__指向null,这里就是所有原型链的终点。

总结

其实我自己还总结了一个简单的方法帮助理解。

就是看当前对象是否是prototype对象,如果是,则当前对象的__proto__一般指向Object.prototype,也可能出于继承而指向别的构造器的prototype;

如果不是,就问是哪个构造器构造的当前对象,当前对象的__proto__就指向那个构造器的prototype。

理解JavaScript的原型链对于进阶学习至关重要,请务必彻底理解。

参考

  1. Inheritance and the prototype chain - MDN
  2. JavaScript权威指南(原书第6版) - Amazon