JavaScript原型链
要搞清楚原型链,我们首先了解什么是
原型?每个函数都有prototype属性,我们称之为原型,又因为这个属性的值是一个对象,所以我们也称为原型对象。那么什么是
对象呢?这里我们要了解在JavaScript中对象是一种引用数据类型。我们可以通过很多种方式来创建一个对象。我们常用构造函数的方式来创建一个对象:
1 | //构造函数 |
那么,函数与对象的关系是怎么样的呢?
- 函数是对象,对象都是通过函数创建的。
- 函数与对象并不是简单的包含与被包含的关系。
在我们上面创建的对象中,通过定义常量实例化后,在原来
构造函数中通过this赋值的方法或者属性,已经在实例化后成为了每个实例的实例属性和实例方法,无法共享公共属性和方法。所以设计出了一个原型对象,来存储这个构造函数的公共属性及方法。
我们再下面一段代码了加深一下理解:
1 | // 构造函数 |
可以看到我们实例对象实例
p1调用到Person这个构造函数的原型对象上的say()方法。但是为什么呢?明明只有在构造函数内部通过this来赋值的属性或者方法才会被实例所继承,为什么在构造函数的原型对象上定义的say方法也能通过实例来调用到呢?这里就引出了原型链这个概念。
实际上
原型对象中存在的构造函数指向了我们function创建的对象。并且每个对象都有一个__proto__属性,这个属性会指向实例对象的构造函数的原型对象,这样使得彼此之间存在一定的指向关系,能够使每个实列化对象能够使用构造函数的原型对象的方法。
而这种指向关系,我们就称之为原型链。图解如下:


我们可以看到,它的
__proto__属性指向了一个function Function的原型对象,该原型对象为JS中所有函数的原型对象,而其__proto__属性也还是指向了function Object的原型对象,所以验证了原型链的尽头为null,这一说法。
在开发的时候,要注意不要通过
实例对象去改变其构造函数的原型对象,这样会对其他通过该构造函数生成的实例对象造成影响。
1 | //开发中需注意点 |
原型链的尽头
我们可以看到,
实例对象的__proto__属性指向了一个构造函数的原型对象,该构造函数的原型对象的_proto_属性指向了Object的原型对象,而其Object的原型对象的_proto_属性指向了null,所以验证了原型链的尽头为null,这一说法。
