本文思路:
原型->原型链->原型继承->基于原型的继承/ES6中的继承->__proto__与prototype
首先我们知道JS中有对象,比如:
var
但是在我们没有对这个对象进行操作之前,这个对象里已经有几个属性/方法了:
那么问题来了:valueOf( ) / toString( ) / constructor 是怎么来?
这里就涉及到一个重要的知识:原型!
答案:它们都是来自于原型里。
原型是什么?原型在哪里?原型和对象的关系?看下面这幅图:
答案:原型就是__proto__指向的那个对象。
1. obj 本身有一个属性 name(这是我们给它加的)
2. obj 还有一个属性叫做 __proto__(它是一个对象)
3. obj.__proto__ 有很多属性,包括 valueOf、toString、constructor 等
4. obj.__proto__ 其实也有一个叫做 __proto__ 的属性,值为 null
当我们读取 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__ 组成的链子一直走的。
这个链子,就叫做:原型链!
到了这里,我们大概明白了原型链上可能会有很多个原型,它们就像Java中的继承关系一样,从顶层的父类一直层层继承。
这就是我个人对原型继承粗略理解。
在ES6之前,我们要手动实现继承的话,就要依赖于原型继承。原理就是改变对象的原型(链),可以想到,当对象的原型变化了,就相当于"父亲"改变了,这样就实现了继承。
在ES6中就没有这么麻烦,直接使用class/extends就能实现继承。
学习ES6中的继承可以看这篇文章的第八点:
pany:ES6新特征总结zhuanlan.zhihu.com学习基于原型的继承可以看这篇文章:
森仪:对js继承的理解zhuanlan.zhihu.com原型、原型链、原型继承、ES6之前基于原型的继承、ES6中Class继承大致已经掌握,然后又碰见了新的问题:
我们发现原型有两个属性可以得到:__proto__ 与 prototype
这篇文章里我们都是用对象的__proto__属性访问原型的,但是在对象还没有被实例化,也就是还处在构造函数阶段的时候,我们就要用 prototype 属性来访问原型(函数名.prototype)。
看这个图:
以上。
PS:如文章存在致命性错误,还请各位知友指出。
推荐:
方应杭:「每日一题」什么是 JS 原型链?zhuanlan.zhihu.comEnd。