4.继承
1、对象冒充
function ClassA(sColor){
this.color = sColor;
this.showColor = function(){
console.log(this.scolor);
}
}
function ClassB(sColor){
this.newMethod = ClassA;
this.newMethod(sColor);
delete this.newMethod;
}
var objA = new ClassA("red");
var objB = new ClassB("blue","Nicholas");
objA.sayColor();//red
objB.sayColor();//blue
objB.sayName();//Nicholas
ClassB继承ClassA。原理 把ClassA作为常规函数来建立继承机制。为ClassB赋予newMethod。然后调用该方法,传递给
它的是ClassB构造函数的参数sColor。最后删除对ClassA的引用,以后不再调用它。
可以多重继承,分别继承两个类。
问题:如果继承的两个类有同名的属性,方法就会发生覆盖问题。
由于这种方法的流行,ECMAScript为Function对象加入了两个新方法,call和apply。
2、call()方法
原理:call()的第一个参数用作this对象。其他参数直接传递给函数自身。
function sayColor(sPrefix,sSuffix){
alert(sPrefix+this.color+sSuffix);
}
var obj = new Object();
obj.color = "red";
sayColor.call(obj,"The color is ","a very nice color indeed");
与继承机制的对象冒充方法一起使用。
function ClassA(sColor){
this.color = sColor;
this.showColor = function(){
console.log(this.scolor);
}
}
function ClassB(sColor,sName){
//this.newMethod = ClassA;
//this.newMethod(sColor);
//delete this.newMethod;
ClassA.call(this,sColor);
this.name = sName;
this.sayName = function(){
alert(this.name);
}
}
3、apply方法
apply 方法有两个参数,用作this的对象和要传递给函数的参数数组。
function sayColor(sPrefix,sSuffix){
alert(sPrefix+this.color+sSuffix);
};
var obj = new Object();
obj.color = "red";
sayColor.apply(obj,new Array("this color is ","very nice color indeed"));
用作继承
function ClassA(sColor){
this.color = sColor;
this.showColor = function(){
console.log(this.scolor);
}
}
function ClassB(sColor,sName){
//this.newMethod = ClassA;
//this.newMethod(sColor);
//delete this.newMethod;
ClassA.apply(this,new Array(sColor));
this.name = sName;
this.sayName = function(){
alert(this.name);
}
}
可以把classB的整个arguments 对象作为第二个参数传递给apply方法。
function ClassB(sColor,sName){
//this.newMethod = ClassA;
//this.newMethod(sColor);
//delete this.newMethod;
ClassA.apply(this,arguments);
this.name = sName;
this.sayName = function(){
alert(this.name);
}
}
4、原型链
继承这种形式原本是用于原型链的。
function ClassA(){
}
ClassA.prototype.color = "red";
ClassA.prototype.sayColor = function(){
alert(this.color);
};
function ClassB(){
}
ClassB.prototype = new ClassA(); //原型链的神奇之处在于此行。
这里把ClassB的prototype 属性设置成了ClassA的实例。
注意:调用ClassA的构造函数时,没有给它传递参数。这在原型链中是标准做法。要确保构
造函数没有任何参数。
与对象冒充相似,子类的所有属性和方法都必须出现在prototype属性被赋值后,因为在它之
前赋值的所有方法都会被删除。 因为prototype属性被替换成了新对象,添加了新方法的原
始对象将被销毁。所以,为ClassB类添加name属性和sayName()方法如下:
function ClassB(){}
ClassB.prototype = new ClassA();
ClassB.prototype.name=" ";
ClassB.prototype.sayName = function(){
alert(this.name);
};
测试代码:
var objA = new ClassA();
var objB = new ClassB();
objA.color = "red";
objB.Color = "blue";
objB.name = "Nicholas";
objA.sayColor();
objB.sayColor();
objB.sayName();
instanceof 对于ClassB的所有实例,instanceof ClassA ClassB 都返回true;
弊端:不支持多重继承。原型链会用另一种类型的对象重写类的prototype属性。
5、混合方式
对象冒充:必须使用构造函数方式,可以传递参数。
原型链:不可以传递参数,不支持多重继承。共享属性和方法(这个优点是网上查的,没有说
服力)
混合模式:用对象冒充继承属性,用原型链继承prototype对象的方法。
function ClassA(sColor){
this.color = sColor;
}
classA.prototype.sayColor = function(){
alert(this.color);
};
function ClassB(sColor,sName){
ClassA.call(this,sColor);
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function(){
alert(this.name);
};
测试代码:
var objA = new ClassA("red");
var objB = new ClassB("blue","Nicholas");
objA.sayColor();
objB.sayColor();
objB.sayName();
by simpman