1 function Foo() { 2 this.value = 42; 3 } 4 Foo.prototype = { 5 method: function() {} 6 }; 7 8 function Bar() {} 9 10 // 设置Bar的prototype属性为Foo的实例对象 11 Bar.prototype = new Foo(); 12 Bar.prototype.foo = 'Hello World'; 13 14 // 修正Bar.prototype.constructor为Bar本身 15 Bar.prototype.constructor = Bar; 16 17 var test = new Bar() // 创建Bar的一个新实例 18 19 // 原型链 20 test [Bar的实例] 21 Bar.prototype [Foo的实例] 22 { foo: 'Hello World' } 23 Foo.prototype 24 {method: ...}; 25 Object.prototype 26 {toString: ... /* etc. */};
一开始,Bar是一个非常简单的函数。
之后:
创建一个Foo函数的实例;
为Bar指定原型;
在其原型上定义一个属性;
使得原型对象的constructor属性指向Bar;
到此为止,Bar由最开始的那个简单的函数变成了:
一:原型对象发生改变,原始Bar本来就有原型对象,现在又为它指定了另一个对象而已。
二:这个充当Bar原型的东东,本身是Foo的实例,现在它发生了改变,一来多了个foo属性,二来它的constructor属性指向了Bar。
现在的Bar作为构造函数,创建了test实例。
先给Bar的原型对象起个名字吧,叫bp。
test作为一个对象,拥有_proto_属性,此属性的指向和构造函数Bar的prototype属性的指向是一模一样的。
而“万夫所指”的那个被叫做原型对象的东东,已经有名字啦,就是bp。
回到bp
bp是构造函数Foo的一个实例。
那么bp是什么?
一:bp是Foo的实例
二:bp中的_proto_属性,和构造函数Foo中的prototype属性的指向一样,是属于Foo的原型对象,名叫fp
到此为止,一切都明了。
Foo的原型对象是fp,
Bar的原型对象是bp,
test的原型对象,就是Bar的原型对象bp。
bp是一个活生生的对象,它的原型对象就是fp。
故而:
test的原型对象是bp
bp的原型对象是fp。
正好应了阮一峰老师说的那样:
每一个对象都有自己的原型,
每一个原型都是对象,也拥有自己的原型。
构造函数的各个实例,共享构造函数原型对象。
定义一次,用到多次?