继承
以下所有提到的方法都是基于原型链,因为javascript的继承是基于原型的继承。
注意:1.instanceof操作符对原型链上所有对象都有效。2.对象字面量重写原型的行为会切断原型链。
基本模式
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//inherit from SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
alert(instance instanceof Object); //true
alert(instance instanceof SuperType); //true
alert(instance instanceof SubType); //true
alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true
优点:实现对象之间的继承,所有子类实例可共享父类方法。
缺点:子类的原型是父类的一个实例,所有子类实例都将共享父类某实例的属性;在创建子类的实例时不能向父类的构造函数传递参数。
借用构造函数
在子类构造函数内部调用超类构造函数
function SuperType(name){
this.name = name;
}
function SubType(){
//inherit from SuperType passing in an argument
SuperType.call(this, "Nicholas");
//instance property
this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas";
alert(instance.age); //29
优点:子类实例不再共享父类某实例的属性,而是拥有同名属性;创建子类的实例时可以向父类的构造函数传递参数;调用父类构造函数放在最前能保证子类的属性不会被父类构造函数重写。
缺点:方法不能复用。
组合模式
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.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
优点:结合基本模式和构造函数的优点。
缺点:调用子类构造函数时必须调用父类构造函数重写子类的属性。
原型式继承
基于已有的对象创建新对象,并不必创建新类型。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
其中ECMAscript5规范了原型式继承,用Object.create()来代替object方法。
优点:方便单例继承,代码量更少。
缺点:同基本继承。
寄生式继承
function createAnother(original){
var clone = object(original); //通过原型式继承创建新对象
clone.sayHi = function (){ //增强对象
alert("Hi");
};
return clone; //返回对象
}
优缺点同原型式继承。
寄生组合式继承
利用继承父类原型的空对象作为子类的原型,再给子类原型添加子类方法。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //create object
prototype.constructor = subType; //augment object
subType.prototype = prototype; //assign object
}
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;
}
inheritPrototype(SubType, SuperType);
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
优点:避免子类继承父类时需要创建一个父类实例。