渐进式的理解JS原型链

147 阅读2分钟
function Girl () {}

Girl.prototype.habits = function () {}

const 刘亦菲 = new Girl()


这里创建了 Girl 这个构造函数,然后在这个构造函数的原型对象上,加了一个 habits 的方法。最后实例化出了刘亦菲这个对象。


说明关系:Girl 这个构造函数在被实例化的时候,会产生一个原型对象。并且让 Girl 的 prototype 指向这个对象,当实例化完成后,刘亦菲作为新的实例,会有一个 __proto__ 的属性,也指向这个原型对象。还会有个 constructor 指向构造她的 Giry 如下:

image.png


所以


console.log(刘亦菲.__proto__ === Girl.prototype) // true
console.log(刘亦菲.constructor === Girl) // true


刘亦菲的 __proto__ 指向的是原型对象,那么这个原型对象的 __proto__ 指向谁呢?回过头来看刘亦菲,她是 Gril 实例化出来的,而 __proto__ 这种属性,只有实例化出来的对象才有。也就是说,是谁把原型对象实例化出来的?答案是 Object。那么根据刘亦菲的 __proto__ 就能推出,这个原型对象的 __proto__ 就会指向 Object 的 prototype


image.png


所以


console.log(刘亦菲.__proto__.__proto__ === Object.prototype) // true


提问:Girl 的 proto 指向谁?


看了刘亦菲和原型对象的 __proto__ ,那么回过头来看看 Girl 的 __proto__ 是谁?Girl 在这里被当成了一个构造函数去看,其本质就是函数。那么它的 __proto__ 就会指向 Function 的 prototype


image.png

所以


console.log(Girl.__proto === Function.prototype) // true


再思考,Girl的 __proto__ 的 __proto__ 又指向谁呢?这时又回到了之前提到过的情况,原型对象的 __proto__ ,就指向 Object 的 prototype 了


image.png




所以


console.log(Girl.__proto.__proto__ === Object.prototype) // true


终结问题:Girl.__proto.__proto__.__proto__ 指的是谁?

问题转化:Object.prototype 的 __proto__ 指的是谁?


毫无疑问,Object.prototype.__proto__ 仍然是个对象,但到了这一步,就不能再按着刚才的思路来了,因为这时会发现:Object的原型对象的 __proto__ 会指向自己,这样就会陷入死循环。所以到了这一步,JavaScript 就被设计为 Object.prototype._

proto_
指向 null,作为原型链的终结点。

image.png



所以


console.log(Object.prototype.__proto__ === null) // true


总结:这就是原型链,上面的每张图之间的关系都可以单独抽出来,说是一条原型链。只不过这条链会延伸出越来越多的关系,到最后这个最为复杂的关系链。这条链,从 Girl 开始,延伸出很多条关系线,最后到 null截止。其实这里还可以继续说说 Object.__proto__ ,但熟悉套路之后,看这张图就能马上看出,Object.__proto__ === Function.prototype。