什么是原型链?
前面几篇博客讲解了JS中的构造函数,原型,prototype与__proto__,以及构造函数、原型与实例三者之间的关系,Function,其实这些知识都是为原型链做准备的。通过这几篇博客,我们知道:
(1)每个构造函数都有一个原型对象(构造函数.prototyoe)
(2)每个原型对象包含一个指向构造函数的指针(构造函数.prototype.constructor)
(3)每个实例对象都会有构造函数 (构造函数会使用new实例化对象)
(4)每个实例对象内部都有一个指向原型对象的指针(实例对象.__proto__)
(5)每个构造函数的原型对象都是一个对象(原型对象中有属性和方法,原型当然是对象啦)
(6)每个函数都是对象,每个函数都是Function类型的实例。var 函数名= new Function();
(7)Function这个构造函数也有原型对象,Function.prototype
也就是说:
凡是对象就有原型, 原型又是对象, 因此凡是给定义一个对象, 那么就可以找到它的原型, 原型还有原型. 那么如此下去, 就构成一个对象的序列. 称该结构为原型链.
使用构造函数创建出对象, 并且没有利用赋值的方式修改原型, 就说该对象保留默认的原型链.
(这里为什么说没有利用赋值的方式修改原型就保持默认的原型链呢,因为后续继承会讲通过原型链实现继承。)
默认原型链结构是什么样子呢?
还是结合例子,画图展示一下:
function Person() {
}
var p = new Person();
// p 具有默认的原型链
还记得,这篇博客中,构造函数、原型、对象三者之间的关系吗?
他们最基本的关系如图:
基本函数的原型结构图
原型对象也是对象,原型对象(Object)也有自己的构造函数,原型对象也有自己的原型,原型对象的尽头就是null。这样就可画出完整的原型链结构图:
通过上图可以清晰的看出,默认的原型链结构就是:
当前对象 -> 构造函数.prototype -> Object.prototype -> null
也可以用对象的__proto__属性进行访问。
别急,还记得说过,每个函数都是Function的实例吧,那么构造函数也是函数,那它也是Function的一个实例,所以结合Function,原型链结构图如下:
Object原型对象没有构造函数,有一个相关的原型对象,通过.__proto__指向null.
描述链式结构
p —> Person.prototype —>Object.prototype—->null
原型链明白之后,那么对于对象的属性搜索原则也就明朗了。
属性搜索原则:
- 当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用;
- 如果没有找到,则去当前对象的原型对象中去查找,如果找到了直接使用;
- 如果没有找到,继续找原型对象的原型对象,如果找到了,直接使用;
- 如果没有找到,则继续向上查找,直到Object.prototype,如果还是没有,若是属性就是undefined,若是方法就报错。