原型链:通过原型链实现的,子类调用父类的方法时会一直沿着原型链往上找到父类的原型对象并调用相应的方法从而实现继承;
本人对原型的理解为上图所示,目前无法简要且切入的用字面语句详解,参考方方老师的解释更易理解:「每日一题」什么是 JS 原型链?
为什么有 valueOf / toString 属性呢?
在我们没有对 obj 进行任何其他操作之前,发现 obj 已经有几个属性(方法)了:
那么问题来了:valueOf / toString / constructor 是怎么来?我们并没有给 obj.valueOf 赋值呀。
要搞清楚 valueOf / toString / constructor 是怎么来的,就要用到 console.dir 了。
上面这个图有点难懂,我手画一个示意图:
我们发现 console.dir(obj) 打出来的结果是:
1. obj 本身有一个属性 name(这是我们给它加的)
2. obj 还有一个属性叫做 __proto__(它是一个对象)
3. obj.__proto__ 有很多属性,包括 valueOf、toString、constructor 等
4. obj.__proto__ 其实也有一个叫做 __proto__ 的属性(console.log 没有显示),值为 null
现在回到我们的问题:obj 为什么会拥有 valueOf / toString / constructor 这几个属性?
答案:
这跟 __proto__ 有关。
当我们「读取」 obj.toString 时,JS 引擎会做下面的事情:
1. 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。
2. 看看 obj.__proto__ 对象有没有 toString 属性,发现 obj.__proto__ 有 toString 属性,于是找到了
所以 obj.toString 实际上就是第 2 步中找到的 obj.__proto__.toString。
可以想象,
3. 如果 obj.__proto__ 没有,那么浏览器会继续查看 obj.__proto__.__proto__
4. 如果 obj.__proto__.__proto__ 也没有,那么浏览器会继续查看 obj.__proto__.__proto__.proto__
5. 直到找到 toString 或者 __proto__ 为 null。
上面的过程,就是「读」属性的「搜索过程」。
而这个「搜索过程」,是连着由 __proto__ 组成的链子一直走的。
这个链子,就叫做「原型链」。