js继承的几种方式

1,对象冒充
function ClassA(sColor){
    this.color=sColor;
    this.sayColor=function(){
        alert(this.color);
    };
}
function ClassB(sColor){
    this.newMethod=ClassA;
    this.newMethod(sColor);
    delete this.newMethod;
}
注意:函数名只是指向它的指针
最后一行删除对ClassA的引用,这样以后就不能再调用它
所有的新属性和新方法都必须在删除了新方法的代码后定义,否则覆盖超类的相关属性和方法
function ClassB(sColor,sName){
    this.newMethod=ClassA;
    this.newMethod(sColor);
    delete this.newMethod;
    this.name=sName;
    this.sayName=function(){
        alert(this.name);
    };
}
为证明前边的有效,运行下面例子
var objA=new ClassA("red");
var objB=new ClassB("blue","Nicholas");
objA.sayColor();
objB.sayColor();
objB.sayName();

改方法支持多重继承,下面这个类继承了ClassX和ClassY
function ClassZ(){
    this.newMethod=ClassX;
    this.newMethod();
    delete this.newMethod;
    this.newMethod=ClassY;
    this.newMethod();
    delete this.newMethod;
}
如果ClassX,ClassY具有同名的属性和方法,ClassY具有最高优先级
由于这种继承方法流行,ECMAScript为Function对象加入了两个新方法,即call()和apply()


2,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.");
在这个例子中,函数sayColor()在对象外定义,即使它不属于任何对象,也可以引用关键字this.对象obj的color属性等于red,调用call()方法时,第一个参数是obj,说明应该赋予sayColor()函数中的this关键字是obj.
要与继承机制的对象冒充方法一起使用该方法,只需将前三行的赋值,调用和删除替换即可:
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);
    };
}
这里想让ClassA的关键字this等于新创建的ClassB对象,因此this是第一个参数,第二个参数sColor对两个类来说都是唯一的参数
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("the color is",",a very nice color indeed"));
该方法也用于替换前三行的赋值,调用和删除新方法的代码:
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);
    };
}
同样,第一个参数仍然是this,第二个是数组,可以把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,原型链
prototype对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。
如果用原型方式重定义前面例子中的类,它们将变为下列形式
function ClassA(){
}
ClassA.prototype.color="red";
ClassA.prototype=sayColor=function(){
    alert(this.color);
};
function ClassB(){
}
ClassB.prototype=new ClassA();
原型链的神奇之处在于突出显示的代码行。这里ClassB的prototype属性设置成ClassA的实例。这很有意义,因为想要ClassA的所有属性和方法,但是有不想逐个将它们赋予ClassB的prototype属性。
特别注意:调用ClassA的构造函数时,没有给它传递参数。这在原型链中的标准做法。要确保构造函数没有任何参数。
与对象冒充相似,子类的所有属性和方法都必须出现在prototype属性被赋值后,因为在它之前赋值的所有方法会被删除。因为protype属性被替换成新对象,添加了新方法的原始对象将被销毁。所以,为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.
例如:
var objB=new ClassB();
alert(objB instanceof ClassA);
alert(objB instanceof ClassB);
都返回"true"
这种方法的弊端:不支持多重继承。记住:原型链会用另一类型的对象重写的prototype属性
5,混合方式
这种继承方式使用构造函数定义类,并未使用任何原型,对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参的构造函数了。开发者该如何选择呢?答案很简单,两者都使用。创建类的最好方式是用构造函数方式定义属性,用原型方式定义方法。这种方式同样适用于继承机制,用对象冒充继承函数的属性,用原型链继承prototype对象的方法,用这两种方式重写前面的例子,代码如下:
function ClassA(sColor){
    this.color=sColor;
}
ClassA.prototype.sayColor=function(){
    alert(this.color);
};
function ClassB(sColor,sName){
    callA.call(this,sColor);
    this.name=sName;
}
ClassB.prototype=new ClassA();
ClassB.prototype.sayName=function(){
   alert(this.name); 
};
在此例子中,继承机制有两行突出显示的代码实现。在第一行中,在ClassB的构造函数中,用对象冒充继承ClassA类的sColor属性。在第二行,用原型链继承ClassA类的方法。由于这种混合方式使用了原型链,所以instanceof运算符仍能正确运行。
下面的例子测试了这段代码:
var objA=new ClassA("red");
var objB=new ClassB("blue","Nicholas");
objA.sayColor();
objB.sayColor();
objB.sayName();

posted @ 2013-12-17 22:14  photoshop爱好者  阅读(75)  评论(0)    收藏  举报