原型和原型链
首先先从一个构造函数开始:
function Person() {...} const p = new Person();
其中,Person
就是一个构造函数, p就是一个实例对象.
每个函数
都有一个属性 prototype
,该属性指向一个对象,即调用该构造函数生成的实例对象的原型.
那么什么是原型呢?
可以这么理解,每个对象A(除了null)在创建的时候都会与之关联另一个对象B,这个对象B就是对象A的原型,对象A会从对象B中继承属性.
此处说是继承也不太恰当,因为继承是指复制属性到本体,而对象可以访问到对象的原型上的属性不是复制下来的,更像是委托访问
那么此时,我们就有了一条关系图:

那么怎么联系实例对象p和p的原型之间的关系呢?
每一个对象(除了null)都有一个属性 __proto__
,该属性会指向该对象的原型.
虽然
__proto__
属性已经被各大浏览器厂商实现,但是其还不能成为一个标准规范.obj.__proto__
可以看作是Object.getPrototypeOf(obj)
的语法糖.
这个时候就会有:

既然实例对象和构造函数都有方法指向实例的原型,那么实例的原型有没有什么属性可以指向其构造函数或者实例吗?
--> 有的,每个实例的原型对象有一个属性 constructor
可以指向关联的构造函数.但是没有属性可以指向对应的实例对象,这是因为实例对象可能会有多个.
这个时候就会有:

那么问题来了,原型也是一个对象,那么既然是对象,就可以用最原始的方法来创建它:
const p_proto = new Object()
也就是说原型对象是由构造函数 Object
实例化而来的.那么我们就可以更新原型对象的关系:

那么p_proto的原型的原型对象是什么呢?(p的原型对象的原型对象的__proto__)
--> 其实是null,原型链已经到头了

众所周知,其实函数也是对象,只不过是一种特殊的对象.
const fn = new Function('a','b','return a+b'); //等价于 function fn(a,b) { return a+b; }
因此,函数Person
也是一个通过new Function
出来的一个实例对象,它的构造函数是Function
.因此有:

同理,原型对象也会指向原型对象的原型.
既然函数也是对象,那么构造函数Function
和 Object
也是对象,他们也有 __proto__
.

因此最终的走向图为: