深入理解原型和原型链

1,354 阅读3分钟

我们创造的每一个函数都有一个prototype(原型)属性。这个属性是一个指针,指向原型对 象。在默认情况下,所有的原型对象都会有一个constructor(构造函数)属性,这个属性包含一个指向prototype属相所在的指针。当调用构造函数创建一个新实例之后,该实例内部将包含一个指针(内部属性),指向构造函数的原型对象。

构造函数创建对象

一:什么是原型?每一个javascrip对象(除null)在创建时都会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型继承。

让我们用一张图表示构造函数和实例原型之间的关系:



二:每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__(内部属性),这个属性会指向该对象的原型。

function Person() {

}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

可以有以下关系图:

实例与实例原型的关系图

三:constructor,每个原型都有一个 constructor 属性指向关联的构造函数。

可以通过代码进行验证:

function Person() {

}
console.log(Person === Person.prototype.constructor); // true

所以再更新关系图:

å®žä¾‹åŽŸåž‹ä¸Žæž„é€ å‡½æ•°çš„å…³ç³»å›¾

综上所述可以得到:(代码表示)

function Person() {

}

var person = new Person();

console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
// 顺便学习一个ES5的方法,可以获得对象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true

在浏览器中可以看出:


实例与原型

当读取实例中是属性时,如果找不到,就会去原型中查找,如果找不到就会去找原型的原型,一直找到最顶层为止。

function person(){
		}
person.prototype.name = "kevin";
var person1 = new person();
person1.name = "disy";
console.log(person1.name);

在浏览器中操作得到结果:


可以看出。删除实例中的name后,向上查找到了原型中的name属性。

原型的原型

原型是一个对象,我们可以用最原始的方式来创建它:

var obj = new Object();
obj.name = 'Kevin'
console.log(obj.name) // Kevin

其实原型对象就是通过 Object 构造函数生成的,结合之前所讲,实例的 __proto__ 指向构造函数的 prototype ,所以我们再更新下关系图:

原型的原型关系图

原型链

文章的开头就讲了:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针 .

假如我们让原型对象等于另一个类型的实例。此时,原型对象将包含一个指向另一个原型的指针。假如,另一个原型又是另一个类型的实例。层层递进,就构成了实例与原型的链条。

注意:Object.prototype的原型呢?

console.log(Object.prototype.__proto__ === null) // true

引用阮一峰老师的 《undefined与null的区别》 就是:

null 表示“没有对象”,即该处不应该有值。

所以 Object.prototype.__proto__ 的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。

所以查找属性的时候查到 Object.prototype 就可以停止查找了。

最后一张图的更新:

原型链示意图


图中的相互的链状结构的关系组成原型链,也就是蓝色部分。










 参考: 《JavaScript高级程序设计》   

               冴羽的博客