继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个是接口实现,一个是继承。而ECMAscript 只支持继承,不支持接口实现,而实现继承方式依靠原型链完成。
1、原型链继承
function Box(){ this.name = 'Lee'; } function Desk(){ this.age = 100; } Desk.prototype = new Box(); //Desk 继承了Box,通过原型,形成链条 var desk = new Desk(); alert(desk.age);
ps:在JavaScript 里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)。原型链继承有两个缺点:1、引用类型的原型问题。2、子类型无法给超类型传参。
2、借用构造函数技术(对象冒充)
function Box(name,age){ this.name = name; this.age = age; } function Desk(name,age){ Box.call(this,name,age); //对象冒充,对象冒充只能继承构造里的信息。原型里的信息无法继承。 } var desk = new Desk('Howie',200); alert(desk.name);
3、组合继承(原型链+对象冒充)
function Box(name,age){ this.name = name; this.age = age; } Box.prototype.run = function(){ return this.name + this.age +'运行中...'; } function Desk(name,age){ Box.call(this,name,age); //对象冒充,第一次Box调用 } Desk.prototype = new Box(); //原型链继承,第二次Box调用
var Desk = new Desk('Howie','100'); alert(Desk.run());
组合式继承是JavaScript 最常用的继承模式;但,组合式继承也有一点小问题,就是超类型在使用过程中会被调用两次:一次是创建子类型的时候,另一次是在子类型构造函数的内部。
4、寄生组合继承
//临时中专函数 function obj(o) { //o表示将要传递进入的一个对象 function F() {} //F构造是一个临时新建的对象,用来存储传递过来的对象 F.prototype = o; //将o对象实例赋值给F构造的原型对象 return new F(); //最后返回这个得到传递过来对象的对象实例 } //寄生函数 function create(box, desk) { var f = obj(box.prototype); //此时f.constructor 指向box f.constructor = desk; //调整原型构造指针,让f.constructor 指向desk desk.prototype = f; } function Box(name, age) { this.name = name; this.age = age; } Box.prototype.run = function () { return this.name + this.age + '运行中...' } function Desk(name, age) { Box.call(this, name, age); //对象冒充 } //通过寄生组合继承来实现继承 create(Box, Desk); //这句话用来替代Desk.prototype = new Box(); var desk = new Desk('Lee',100); alert(desk.run());
寄生组合继承,解决了两次调用的问题