在继承时,出于效率的考虑,我们会尽可能地将一些可重用的属性和方法添加到原型中去,如果如此,我们就可以仅依靠原型就完成继承关系的构建。
function Shape() {}
Shape.prototype.name = 'shape';
Shape.prototype.toString = function() {return this.name;};
function TwoDShape() {}
TwoDShape.prototype = Shape.prototype;
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D shape';
function Triangle(side,height) {
this.side = side;
this.height = height;
}
Triangle.prototype = TwoDShape.prototype;
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function() {return this.side*this.height/2;}
var a = new Triangle(2,10);
a.toString(); //"Triangle"
这样写,只继承于原型,执行a.toString()时,JavaScript引擎会先查看a对象中有没有toString()方法,找不到就会去搜索该对象的原型属性,此时该原型已经指向了TwoDShape的原型,而后者指向的又是Shape.prototype,且这里采用的是引用传递,因此就能精简查询步骤。
但它存在着副作用,由于子对象与父对象指向的是同一个对象,所以一旦子对象对其原型进行修改,父对象也会随着被改变,甚至所有的继承关系也是如此。因此,我们可以通过利用一个临时构造器来打破这种连锁关系,即创建一个空函数f(),并将其原型设置为父级构造器。然后,我们既可以用new F()来创建一些不包含父对象属性的对象,同时又可以从父对象prototype属性中继承一切。
function TwoDShape() {}
//----------临时构造器----------
var F = function() {};
F.prototype = Shape.prototype;
TwoDShape.prototype = new F();
TwoDShape.prototype.constructor = TwoDShape;
TwoDShape.prototype.name = '2D shape';
function Triangle(side,height) {
this.side = side;
this.height = height;
}
//----------临时构造器----------
var F = function() {};
F.prototype = Shape.prototype;
Triangle.prototype = new F();
Triangle.prototype.constructor = Triangle;
Triangle.prototype.name = 'Triangle';
Triangle.prototype.getArea = function() {return this.side*this.height/2;}
基于此,我们可以将这些实现继承关系的代码封装起来
function extend(Child, Parent) {
var F = function() {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
}