参考《JavaScript 高级程序设计(第3版)》
在 JavaScript 中实现继承,有两种基本方法,一种是使用原型链,令子类的原型是父类的一个对象;另一种是借用构造方法,在子类的构造方法中使用call方法或apply方法调用父类的构造函数。但这两种方法基本上都很少单独使用,而是采用组合式的继承。
一、原型链
//定义父类
function Person(){
this.type = "person";
}
//定义父类的方法
Person.prototype.getType = function(){
return this.type;
}
//定义子类
function Man(){
this.type = "man";
this.name = "Jack";
}
//利用原型链实现继承
Man.prototype = new Person();
//定义子类的方法
Man.prototype.getName = function(){
return this.name;
}
//重写父类的方法
Man.prototype.getType = function(){
return this.type;
}
利用原型链实现继承最重要的是:子类.prototype = new 父类();
特别需要注意的是定义子类的方法或是重写父类方法必须在利用原型链实现继承之后,而且不可使用字面量添加方法,否则会重写原型,也就没了继承。
原型链方法主要存在的问题有两点:
1、创建子类对象时无法向父类构造函数传递参数,因为只有子类的原型才有调用父类的构造函数。
2、如果父类构造函数中定义了引用类型,那么这个引用类型会成为子类原型的一个属性,也就成为了所有子类的一个共享属性,一个子类对象对该属性的修改会影响所有的子类对象。
二、借用构造函数
//定义父类
function Person(name){
this.name = name;
this.category = ["man","women"];
}
//定义子类
function Man(){
//调用父类构造方法实现继承,还可实现传参
Person.call(this,"Jack");
}
借用构造函数就是在子类构造函数中调用父类构造函数,这样一个直接的好处就是创建子类对象的时候可以传参数,而且父类构造函数中定义的引用类型属性会成为各个子类对象的独占属性。
但是,借用构造函数存在的问题是父类原型中定义的方法在子类中是不可见的,也就无法实现重写。
三、组合继承
将原型链继承和借用构造函数方法继承的优点结合起来,扬长避短。
分为以下5个主要步骤:
1、将私有属性定义在构造方法中
2、将共有方法定义在原型中
3、子类构造方法利用call或apply调用父类构造方法
4、子类的原型指向父类对象
5、子类原型的constructor属性指向子类的构造方法
//定义父类构造方法,包括私有属性
function Person(name){
this.name = name;
this.category = ["man","woman"];
}
//定义父类的共有方法
Person.prototype.sayName = function(){
alert(this.name);
}
//定义子类的构造方法
function man(name, age){
//调用父类的构造方法
Person.call(this,name);
this.age = age;
}
//定义子类的原型
Man.prototype = new Person();
//定义子类原型的constructor属性
Man.prototype.constructor = Man;
//定义子类的方法
Man.prototype.sayAge = function(){
alert(this.age);
}
Man的对象也可调用sayName方法。