方法链、作用域链和原型链(三)——原型链
每一个javascript对象(null除外)都有一个prototype属性(这个属性引用了一个对象,即原型对象),都从原型继承属性。
所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过javascript代码Object.prototype获得对原型对象的引用。通过关键字new和构造函数调用创建的对象的原型就是构造函数的prototype属性的值。因此,使用{}和通过new Object()创建的对象,都继承自Object.prototype。
没有原型的对象不多,Object.prototype是其中之一,它不能继承任何属性。其他原型对象都是普通对象,都具有原型。所有的内置构造函数(以及大部分自定义的构造函数)都具有一个继承自Object.prototype的原型。如:Date.prototype的属性继承自Object.prototype,因此通过new Date()创建的Date对象的属性同时继承自Date.prototype和Object.prototype。这一系列链接的原型对象就是所谓的”原型链“ (prototype chain)。
有如下代码:
function Foo() { this.value = 42; } Foo.prototype = { method: function() {} }; function Bar() {}
// 设置Bar的prototype属性为Foo的实例对象 Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World'; // 修正Bar.prototype.constructor为Bar本身 Bar.prototype.constructor = Bar; var test = new Bar() // 创建Bar的一个新实例 // 原型链 test [Bar的实例] Bar.prototype [Foo的实例] { foo: 'Hello World' } Foo.prototype {method: ...}; Object.prototype {toString: ... /* etc. */};
上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此,它能访问 Foo 的原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是重复使用它原型上的那个实例;因此,所有的 Bar 实例都会共享相同的 value 属性。
当查找一个对象的属性时,优先查找自己的属性,然后沿着原型链一直往顶层Object找,如果没有找到,则返回undefined,这个有点类似作用域链中的变量查找。