原性链继承方法中,JavaScript是通过另一个类的实例进行继承的(实际是用一个构造器函数的实体去覆盖另一个对象的原型)。如下代码:
TwoDShape.prototype = new Shape();
Triangle.prototype = new TwoDShape();
需要直接用new Shape()构造一个实体,然后才能通过该实体的属性完成相关的继承工作,而不是直接继承自Shape()构造器。
这中方法也确保了对Shape()进行任何修改都不会影响TwoDShape(),因为后者继承的只是前者所创建的一个实体
上面的操作后,会对对象的constructor属性产生负面影响,因此需要重置constructor属性:
TwoDShape.prototype.constructor = TwoDShape;
Triangle.prototype.constructor = Triangle;
一种更好的利用原性链继承的方法是,将类中的固定属性或者共享属性不放在构造器函数的定义中,而直接放在原型上。这样在每次new创建新对象时,不会产生过多的内存空间,提高效率:
function Shape(){ function Shape(){}
this.name =‘shape’; 《=》 Shape.prototype.name =‘shape’;
}
但是对于那些每个实体值都不一样的属性,还是需要在构造器函数中定义的
另外需要注意,使用这种方法时,一定要先完成继承关系的构建,再扩展原型对象,否则继承会覆盖对象的扩展,如下代码就会使得原型中的属性值覆盖该对象内特有的属性值:
TwoDShape.prototype.name = ‘2D shape’;
TwoDShape.prototype = new Shape(); //这里就会将name重写为shape
总结:将一些可重用的属性和方法添加到原型中去
上面的方法,通过继承new Shape()实体的方式,会将Shape的属性设定为对象自身属性,这样的代码是不可重用的,可以采取下面”直接继承于原型”的方法来实现继承:
TwoDShape.prototype = Shape.prototype;
这种方法的好处是,当查询一个该对象不存在的属性,在其上层存在的属性时,会缩短查询链的长度。但是缺点是,由于子对象和父对象都继承自同一个对象,因此一旦子对象对原型进行了修改,父对象也会随机被改变。比如下面的代码,对子对象的name值修改,会同样修改父对象:
Triangle.prototype.name = ‘Triangle’ //之后Shape的name也变成了Triangle
解决上面的问题可以使用临时构造器new F(),思想是创建一个临时构造器来充当中介。创建一个空函数f(),并将其原型设置为父级构造器,然后既可以用newF()创建一些不包含父对象属性的对象,同时又可以从父对象prototype属性中继承所有信息。
(其实就是通过中介,让子对象的修改作用到中介构造器上,不对父对象产生影响)
var F = function(){};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape; //重写构造函数
通过这种方法我们就可以在保持原性链的基础上使父对象的属性摆脱子对象的影响了
将继承的方法封装成一个函数extend
[javascript] view plain copy print?在CODE上查看代码片派生到我的代码片
function extend(Child, Parent){
var F = function(){};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor =Child;
Child.uber = Parent.prototype;
}
这样就可以如下进行继承了:
extend(TwoDShape, Shape);
上面的也是YUI框架实现继承的方法,在YUI中如下进行继承:
YAHOO.lang.extend(Triangle, Shape); |
|