【转】什么是 JS 原型链?

我们知道 JS 有对象,比如 var obj = { name: 'obj' } 我们可以对 obj 进行一些操作,包括: 「读」属性 「新增」属性 「更新」属性 「删除」属性 下面我们主要来看一下「读」和「新增」属性。 为什么有 valueOf / toString 属性和方法 hasOwnPrototype / constructor 呢? 在我们没有对 obj 进行任何其他操作之前,发现 obj 已经有几个属性(方法)了: image.png 那么问题来了:valueOf / toString / constructor 是怎么来?我们并没有给 obj.valueOf 赋值呀。 要搞清楚 valueOf / toString / constructor 是怎么来的,就要用到 console.dir 了。 image.png 上面这个图有点难懂,我手画一个示意图: image.png 我们发现 console.dir(obj) 打出来的结果分析 obj 本身有一个属性 name(这是我们给它加的) obj 还有一个属性叫做 __proto__(它是一个对象) obj.__proto__ 有很多属性,包括 valueOf、toString、constructor 等 obj.__proto__ 其实也有一个叫做 __proto__ 的属性(console.log 没有显示),值为 null 现在回到我们的问题:obj 为什么会拥有 valueOf / toString / constructor / hasOwnPrototype这几个属性? 答案: 这跟 __proto__ 有关。 当我们「读取」 obj.toString 时,JS 引擎会做下面的事情: 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。 看看 obj.__proto__ 对象有没有 toString 属性,发现 obj.__proto__ 有 toString 属性,于是找到了 所以 obj.toString 实际上就是第 2 步中找到的 obj.__proto__.toString。 可以想象, 如果 obj.__proto__ 没有,那么浏览器会继续查看 obj.__proto__.__proto__ 如果 obj.__proto__.__proto__ 也没有,那么浏览器会继续查看 obj.__proto__.__proto__.proto__ 直到找到 toString 或者 __proto__ 为 null。 上面的过程,就是「读」属性的「搜索过程」。 而这个「搜索过程」,是连着由 __proto__ 组成的链子一直走的。 这个链子,就叫做「原型链」。 共享原型链 现在我们有另一个对象 var obj2 = { name: 'obj2' } image.png 那么 obj.toString 和 obj2.toString 其实是同一个东西,也就是obj2.__proto__.toString。 这有什么意义呢? 如果我们改写 obj2.__proto__.toString,那么 obj.toString 其实也会变! 这样 obj 和 obj2 就是具有某些相同行为的对象,这就是意义所在。 差异化 如果我们想让 obj.toString 和 obj2.toString 的行为不同怎么做呢? 直接赋值就好了: obj.toString = function(){ return '新的 toString 方法' } image.png 总结: 「读」属性时会沿着原型链搜索。 「新增」属性时不会去看原型链(但是如果你给这个属性加了一些配置,则不一样,以后讲)。

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):