在JavaScript秘密花园( 案例:
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. */};
分析: 1 Foo&Foo.prototype
function Foo() {this.value = 42;}
Foo的prototype指向了Foo.prototype,Foo.prototype的constructor指向了Foo。此时Foo.prototype.constructor=Foo。另外,Foo.constructor指向了Function。后面都用图来表示,更清晰。
2 Foo.prototype
Foo.prototype = {method: function() {}};
由于Foo.prototype通过{}创建了一个新的对象,这个对象继承了Object.prototype。所以,Foo.prototype.constructor指向了Object。
3 Bar&Bar.prototype
function Bar() {}
Bar和第一步的Foo很像,什么都不说了。
4 Bar.prototype&Foo.prototype
// 设置Bar的prototype属性为Foo的实例对象Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World';
Bar.prototype创建了Foo的对象实例,根据原型链回溯原理,Bar.prototype回溯到Foo.prototype,又因为Foo.prototype的constructor指向Object,所以Bar.prototype的constructor也指向了Object,Bar.prototype拥有了value属性和method属性。不同的是,Foo.value改变了之后,Bar.prototype.value不会随之改变。而Foo.prototype.method改变了之后,Bar.prototype.method会随之改变。也就是说,Foo.prototype中的属性会共享到Bar.prototype中。 如果执行的是Bar.prototype=Foo,就不会执行Foo.prototype,而是指向Foo,原型链会回溯到Function.prototype。这样的话,method就不会出现在Bar.prototype上。
5 Bar.prototype
// 修正Bar.prototype.constructor为Bar本身Bar.prototype.constructor = Bar;
这里什么都不说了。在下面一步中详解。
6 test
var test = new Bar() // 创建Bar的一个新实例
不得不说,高潮来了。 如果没有第5步的修正,那么根据回溯原理,test.constructor是指向Object的,为了让test.constructor指向Bar,所以执行了第5步。那么意义何在?看了 test对象继承了Bar.prototype,而Bar.prototype又继承了Foo.prototype,所以可以访问method。同时,也可以访问Foo的实例属性value。因为是Bar.prototype创建了Foo的实例,所以new Bar()不会创建新的Foo实例,而是重复使用Bar.prototype创建的那个Foo实例。所有的Bar实例都会共享Bar.prototype.value属性。