A) 关于prototype chain有几点说明:
a. 这个链的终点是Object的prototype对象:Object.prototype
b. 所有的对象在默认的情况下都有一个原型(__proto__).
c. 原型本身也是对象,所以每个原型自身又有一个原型(__proto__),除了Object.ptototype.
关于c这个观点可以用一下面的小程序来证明:
function A(){}
console.log(A.prototype.__proto__);//Object {}
console.log(Object.prototype.__proto__);//null
就这上面两个输出,下面做详细的分析,并说明这个proto链是怎么形成的。
1) 先定义一个简单的函数并创建该函数的对象 var a = new A(); 注意,这里a,没有自己的属性,它的所有的属性都从原型对象上继承而来)现在看看内存中这个对象的具体情况
图 1.1
观察图1.1,可以发现a对象的__proto__属性,这个论证了观点b的正确性。观察prototype对象有一个__proto__属性(绿色方框所示)。这个就说明了观点b的正确性。
但是,prototype的__proto__所代表的对象是谁呢?查看@37891发现,这个对象是一个Object对象,其实说白了就是Object.prototype所指向的对象。下面给出该对象的内存情况:
图 1.2
观察这个对象的constructor,其指向Object的构造器。对比图1.1可以发现,这个对象是没有__proto__属性的,这个对象正是a对象所在的proto链条的终点:Object.pototype.
结合上面的说明,可以得到如下图示:
注意:沿着红色箭头组成了proto链!!!所以console.log(A.prototype__proto__)为Object{},而Object.prototype.__proto__为null.
B) 通过这个prototype chain可以实现属性的继承,例程如下:
function A(x){
this.x = x ;
}
function B(y) {
this.y = y;
}
B.prototype = new A(1);
function C(z) {
this.z = z;
}
C.prototype = new B(2);
var c = new C(3);
var sum = c.x+c.y + c.z;//sum == 6
可以通过chrome浏览器的Take Heap Snapshot来查看对象c的prototype chain。如下图
图 1.4
先逐步分一下各个对象的内存分析图:查看一下@14285对象(A的对象)的prototype chain:(留意一下@后面的数字)。
用图形表现其prototype chain如下:
图1.6
通过上图分析,有如下关系:
a.__proto__ === A.prototype,
A.prototype.__proto__===Object.prototype
再看看@14295所代表的对象(B的对象)的prototype chain:
图1.7
用图形表现其prototype chain如下:
图1.8
b.__proto__ === B.prototype
B.prototype.__proto__ === A.prototype
A.prototype.__proto__ === Object.prototype
说明:图1.8的B.prototype所代表的对象,其实是图1.6中的对象a,因为B.prototype的@后面的数字和a对象@后面的数字是一样的。所以在这里特地把它们的颜色标识为绿色,以示为同一个对象。其余颜色相同的@+数字,代表着同样的意思。
所以图1.8和图1.7合并起来可以另外表示为:
到这里,B的prototype chain已经和A的prototype chain连接起来了。链接起来的关键代码就是B.prototype = new A(1);
同理,再看看对象c的prototype chain:
图 2.0
用图形表示为:
图 2.2
C.__proto__=== C.prototype
C.prototype. __proto__ == a
注意蓝色@14295,可以得出c. __proto__== b,在代码中体现为C.prototype = new B(2);
所以图2.1还可以表示为:
同时也可以发现,javascript对象属性搜索的过程是由近到远的顺序,如果c对象中有了y属性,那么c.prototype的属性y是不会访问到的。
Var c = new (3);
c.y = 4;//
var sum = c.x +c.y ;//==5而不是==3
注意代码c.y = 4;这是个赋值操作,而不是取值操作;对于赋值操作,javascript总是在原始对象(在这里是c对象)创建属性或者对已有的属性赋值,而不会去修改原型链。在javascript中只有查询属性(取值操作)时才会体现到继承的存在,而设置属性则和继承无关。