上一篇随笔有提到过原型链的问题,这次就讲一下原型链。
讲原型链之前要先说一下什么是原型对象。
原型对象:原型对象是新对象的模板,它将自身的属性通过this共享给新对象。一个对象不但可以享有自己创建时和运行时定义的属性,而且可以享有原型对象的属性。
也可以简单理解成原型对象就是父类,新的对象就是继承了父类的属性和方法的子类,但这种理解又略显片面
1 function a(){ 2 this.b=b; 3 this.c=function(){alert("hi")}; 4 } 5 6 var R = new a(); //这里的a就是原型对象,R继承了a的属性和方法
现在再来说一下原型链,在每个函数对象创建的时候,都会自带一个prototype的属性,这个属性相当于一个指针,指向他本身的原型对象,这个原型对象里包含着自定义的方法属性。
举个例子:实例(_proto)→原型对象(constructor)→构造函数
-
prototype:构造函数中的属性,指向该构造函数的原型对象。
-
constructor:原型对象中的属性,指向该原型对象的构造函数
-
_proto_:实例中的属性,指向new这个实例的构造函数的原型对象
可能看到这里,对构造函数的原型对象又有点迷惑了,上面讲到a就是原型对象,但是a同时也是构造器。
再补充一点:原型对象就是一种特殊的对象,构造函数创建时自动生成;与构造函数形成一一对应,如同人和影子般的关系。
过程如下:
1 var temp = new f1(); 2 3 f1. prototype = temp; 4 5 //就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype
但这种理解是片面的,因为原型对象中不包含构造函数里的属性和值,是一个空的容器。
而实例就是通过构造函数实例出来的对象。与实例一样,原型对象就是构造函数实例出来的一个普通对象
可能这一块比较绕,原型对象是在构造函数定义完成时创建一次,但是实例是new一次就通过构造函数构造一次,是属于一对多的关系。
总结: 构造函数中的属性和方法仅为声明和定义,一旦实例化工作完成后。实例对象自身的属性和方法与构造函数将不在存在关联关系。原型对象与实例对象形成“备胎”关系,当通过对象访问属性或方法时,程序会优先搜索对象本身的属性或方法,不存在才会访问原型对象的方法或者属性。
所以考虑到内存的问题,当一个实例需要用到多个方法时,甚至是多个实例需要用到多个同样的方法时,最好的策略就是把方法放在原型对象上,而构造器上仅存放属性,这样能使代码更具有可读性。
讲到方法放在原型对象上时,又要补充一个点,不要以字面量形式的去定义方法或者属性,这样会重写整个原型对象,原型链也会导致变化。应该以添加的方式去定义
1 //这样会重写整个原型 2 Fn.prototype = { 3 c : function() { 4 return this.a + this.b; 5 } 6 } 7 8 //应该以这种形式添加 9 Rocn.prototype.newFunction = function() { 10 document.write('此方法是通过prototype继承后实现的'); 11 }
注意:属性遮蔽 (property shadowing) 即是构造函数内有属性a,在原型上重写属性a,原型上的属性a会被遮蔽,a的值为构造函数上的值。
只要搞懂各种引用指针的指向,就可以清楚地知道原型链的每一部分的指向,原型链的用途就是当需要检索某一属性或者方法时,会通过这些指向,依次检索到相对应标识符的位置为止。
题外:大家可以思考一下construction的作用和功能。我个人的理解就是为了将实例的构造器的原型对象暴露出来
浙公网安备 33010602011771号