相信有不少已经看过不少关于原型链的文章的小伙伴仍觉得这个概念是一团乱麻,我这在再揉碎掰开来谈谈(本文仅辅助理解原型链,相关知识点可以参考最下方的参考文章)
首先,我们在谈原型的时候,我们究竟在谈论什么?
“你说的原型是prototype还是__proto__还是一些别的什么东西?”,
别急,先把相关术语列出来:
原型链,对象,实例对象,原型对象,实例,prototype,__proto__,constructor,函数,构造函数
为了讲解我们需要一些工具人:
function A(){
this.name = "Alan";
}
let a = new A();
- 对象
在js里,万物皆对象,函数(Function也是对象)。这里的对象,不是Object(Object是js的一种数据类型)。
- 实例对象
new出来的对象,比如上面代码块里的a
- 实例
就是实例对象的简称了
- 函数
函数大家都懂,这里说下函数和对象的关系,所有函数都是对象,而对象又是由函数创建的(是不是有点像先有鸡还是先有蛋?)[1]
- 构造函数
用于创建实例的函数,比如代码块里的A,可以补充下知识点:普通函数和构造函数的区别[2]
- prototype/原型对象
prototype即原型对象,原型对象就是prototype,这两个是同一个东西。
1.prototype是函数独有的,为什么强调独有,因为对象没有!
2.prototype是函数的一个属性,属性,属性!强调的原因是有些小伙伴看到prototype/原型对象会产生一种“这个prototype代表的东西是不是比这个函数高一个层级的东西”。 比如,A.prototype和A.name是一个性质的东西。
3.prototype是一个对象,对象,对象(意味着它是由Object创建的)
- __proto__
__proto__是对象都有的一个属性(意味着函数的话既有__proto__,也有prototype,而非函数的对象只有__proto__,没有prototype)
__proto__和protoype的关系形象的表述就是儿子的__proto__ === 父亲的prototype
每个对象都有__proto__,这是一个JavaScript 的非标准但许多浏览器实现的属性,用于访问该对象的构造函数的prototype(这句话是不是有点绕了,没关系,请结合下面原型链图解就很清晰了)
- 原型链
这就是原型链!:下面贴下代码佐证:
看到这,小伙伴肯定会问了,这不对呀,A和Object的__proto__有什么用?指向哪里?
我们解释术语的时候是不是说过:“所有函数都是对象,而对象又是由函数创建的”
也就是说 A 和 Object 都是由 Function 构造的,
请看下图:
代码:
总结:通过两张原型图,还是可以看出原型链的逻辑还是很清晰的:
在这个逻辑链条里,有四个对象:实例a,构造函数A,Object ,Function
1.对象的__proto__指向创建他的对象的prototype
2.prototype是一个对象,结合1,这下你明白为什么A.prototype.__proto__指向Object.prototype了吧,对,A.prototype是由Object创建的对象
- constructor
1.constructor 指向该对象的构造函数(即a.constructor === A , A.constructor === Function)
所以可以通过constructor来访问爸爸
即儿子的constructor === 爸爸
2.xxx.prototype.constructor 指向当前内置函数对象的引用(即A.prototype.constructor === A)
总结下来,谨记以下几条:
1.prototype是函数独有的对象,__proto__是人人都有
2.儿子的__proto__ === 爸爸的prototype
3.儿子的constructor === 爸爸
4.X的prototype.constructor === X(可以理解为3的变式)
参考:MDN 继承与原型链
六尺帐篷 深入理解javascript中的原型
立志做一个好的程序员 js中Object.proto===Function.prototype
[1]ABC袁 js中对象与函数的关系
[2]Darcyxz js中普通函数和构造函数的区别