function Person() {}
let person = new Person();
console.log(person.__proto__ === Person.prototype);
// true
console.log(person.__proto__ === Object.getPrototypeOf(person)); // true
注意: 当然,在这里我们要提一嘴,__proto__ 在 web 标准中,以及删除,但是一些浏览器目前还是支持的。
function Person() {}
console.log(Person === Person.prototype.constructor);
// true
所以我们继续更新关系图:
到目前为止,我们已经得出来一些结论了。
function Person() {}
let person = new Person();
console.log(person.__protp__ === Person.prototype); //true
console.log(Person.prototype.constructor === Person); // true
原型与原型链
原型
构造函数创建对象
我们来写一个构造函数用来创建一个对象
从例子中,我们使用
new
创建了一个实例对象person
。这我们都是可以理解的,
new
创建实例对象。prototype
每一个函数都有一个
prototype
属性,那么这个属性指向什么呢?其实,函数的
prototype
属性指向了一个对象,这个对象就是调用该构造函数而创建的实例的原型,也就是例子中,person
的原型。我们来打印一下
Person
的prototype
,来看看是什么。说了这么多,还是不知道什么是原型(0_o)。我们可以这样来理解原型:每一个 JS 对象(null 除外)在创建的时候就会有一个与之关联的另一个对象,而这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。
我们简单来表示一下构造函数与实例原型之间的关系:
我们从这张图中,可以看出,
Object.prototype
表示实例原型。 那么我们该怎么表示实例(person
)与实例原型(Person.prototype
)之间的关系呢?所以我们来看看第二个属性__proto__
这是每一个 JS 对象(除了
null
) 都具有的一个属性,叫__proto__
,这个属性会指向该对象的原型。我们来验证一下。
注意: 当然,在这里我们要提一嘴,
__proto__
在web
标准中,以及删除,但是一些浏览器目前还是支持的。于是,我们可以将图进行更新了:
我们现在,构造函数指向原型,实例指向原型,那么原型能否指向构造函数或者指向实例呢?
其实这时候我们就要提到下一个属性了,但是,指向实例的是没有的,因为一个构造函数可以生成多个实例。
constructor
这是我们提到的第三个属性了,而这个属性,就是用来实现由原型指向构造函数,每一个原型都会有一个
constructor
属性来指向关联的构造函数。所以我们继续更新关系图:
到目前为止,我们已经得出来一些结论了。
了解了构造函数、实例原型和实例之间的关系后,我们来看看实例和原型的关系:
实例与原型
在我们读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就会去找原型的原型,直到最顶层为止。
从例子来看,我们给原型对象添加了
name
属性,然后在给实例对象添加了name
属性,而首先打印时,打印了实例对象的name
。但是当我们删除了实例对象的
name
属性时,在实例中就找不到该属性,则会从实例的原型是那个去查找,所以在Person.prototype
中找到。但是,如果我们的原型中没找到呢?原型的原型又是什么呢?
原型的原型
原型是什么?其实原型也是一个对象,既然是对象,那我们就可以用
new Object()
来创建它:而我们再来看一下,Person.prototype 与 Object 的关系.
其实原型对象就是通过
Object
构造函数生成的,实例的__proro__
指向构造函数的prototype
,现在我们再来更新一下关系图:原型链
其实,看完原型的原型,还是会有疑问,Object.prototype 的原型是什么呢?
其实就是
null
,我们可以来验证一下:而
null
是什么呢?因为
Object.prototype.__proto__
的值为null
。所以查找属性的时候其实查到Object.prototype
就可以停止了。我们在来更新一下关系图:
那什么是原型链呢?相互关联的原型组成的链状结构就是原型链,也就是这条红色的线。
补充
你以为这就结束了吗?
我们来看看在来补充一些神奇的事情,我们来看看打印。
经过测试我们会发现,都会
true
。这意味着什么呢?
Person
函数的原型是Function.prototype
Function.prototype
也是Object
构造函数的__proto__
Function.prototype.__proto__
就是Object.prorotype
于是,我们的图就可以更新为如下关系图:
至此,我们的关系图已经基本完善。
再次,我也需要补充一张找到的图,应该说,真的很好,因为我自己画的比较乱。(0_o)