1、【原型链继承】实现的本质是重写原型对象,代之以一个新类型的实例。实际上不是SubType的原型的constructor属性被重写了,而是SubType的原型指向了另一个对象——SuperType的原型,而这个原型对象的construtor属性指向的是SuperType
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //继承了SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue());//true
[注意1]谨慎地定义方法,给原型添加方法的代码一定要放在替换原型的语句之后
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //继承了SuperType SubType.prototype = new SuperType(); //添加了新方法 SubType.prototype.getSubValue = function(){ return this.subproperty; } //重写超类型的方法 SubType.prototype.getSuperValue = function(){ return false; } var instance = new SubType(); alert(instance.getSuperValue());//false
[注意2]通过原型链实现继承时,不能使用对象字面量创建原型方法,这样做会重写原型链
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //继承了SuperType SubType.prototype = new SuperType(); //使用字面量方法添加新方法会导致上一行代码无效 SubType.prototype = { getSubValue : function(){ return this,subproperty; }, someOtherMethod : function(){ return false; } }; var instance = new SubType(); alert(instance.getSuperValue());//error
[缺点1]在创建子类型的实例时,不能向超类型的构造函数中传递参数
[缺点2]包含引用类型值的原型属性会被所有实例共享
function SuperType(){ this.colors = ['red','blue','green']; } function SubType(){} //继承了SuperType SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push('black'); alert(instance1.colors);//'red,blue,green,black' var instance2 = new SubType(); alert(instance2.colors);//'red,blue,green,black'
2、【借用构造函数继承(又叫伪造对象或经典继承)】在子类型构造函数的内部调用超类型构造函数,因此通过使用apply()和call()方法也可以在将来新创建的对象上执行构造函数
function SuperType(){ this.colors = ['red','blue','green']; } function SubType(){ //继承了SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push('black'); alert(instance1.colors);//'red,blue,green,black' var instance2 = new SubType(); alert(instance2.colors);//'red,blue,green'
[优点]传递参数
function SuperType(name){ this.name = name; } function SubType(){ //继承了SUperType,同时还传递了参数 SuperType.call(this,"Nicholas"); //实例属性 this.age = 29; } var instance = new SubType(); alert(instance.name);//"Nicholas" alert(instance.age);//29
[注意]为了确保SuperType构造函数不会重写子类型的属性,可以在调用超类型构造函数后,再添加应该在子类型中定义的属性
function SuperType(name){ this.name = name; this.age = 30; } function SubType(){ //实例属性 this.age = 29; //继承了SUperType,同时还传递了参数 SuperType.call(this,"Nicholas"); } var instance = new SubType(); //实例属性被重写为SuperType构造函数的属性 alert(instance.age);//30
[缺点1]无法实现函数复用
[缺点2]在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式
3、【组合继承(又叫伪经典继承)】将原型链和借用构造函数的技术组合到一起,从而发挥二者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性,成为JavaScript中最常用的继承模式。
function SuperType(name){ this.name = name; this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name,age){ //继承属性 SuperType.call(this,name); this.age = age; } //继承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); } var instance1 = new SubType("Nicholas",29); instance1.colors.push("black"); alert(instance1.colors);//'red,blue,green,black' instance1.sayName();//"Nicholas" instance1.sayAge();//29 var instance2 = new SubType("Greg",27); alert(instance2.colors);//'red,blue,green' instance2.sayName();//"Greg" instance2.sayAge();//27