JavaScript 繼承機(jī)制的實(shí)現(xiàn)(待續(xù))
更新時(shí)間:2010年05月18日 01:18:26 作者:
JavaScript繼承機(jī)制的實(shí)現(xiàn),后期會(huì)有一些補(bǔ)充。
1.對(duì)象冒充
原理:構(gòu)造函數(shù)使用this關(guān)鍵字給所有屬性和方法賦值(即采用類聲明的構(gòu)造函數(shù)方式)。
因?yàn)闃?gòu)造函數(shù)只是一個(gè)函數(shù),所以可使ClassA的構(gòu)造函數(shù)成為ClassB的方法,然后調(diào)用它。ClassB就會(huì)收到ClassA的構(gòu)造函數(shù)中定義的屬性和方法。
例如:
下面方式定義的ClassA和ClassB:
function ClassA(sColor){
this.color=sColor;
this.sayColor=function(){
alert(this.color);
};
}
function ClassB(sColor){
}
關(guān)鍵字this引用的是構(gòu)造函數(shù)當(dāng)前創(chuàng)建的對(duì)象。
不過(guò)在這個(gè)方法中國(guó),this指向的是所屬的對(duì)象。這個(gè)原理把ClassA作為常規(guī)函數(shù)來(lái)建立繼承機(jī)制,而不是作為構(gòu)造行數(shù)。
如下使用構(gòu)造函數(shù)ClassB可以實(shí)現(xiàn)繼承機(jī)制:
function ClassB(sColor){
this.newMethod=ClassA;
this.newMethod(sColor);
delete this.newMethod;
}
這段代碼中,為(但我覺得這里應(yīng)該是"把")ClassA賦予了方法newMethod(記住函數(shù)名只是指向它的指針)。然后調(diào)用該方法,傳遞給它的是ClassB的構(gòu)造函數(shù)的參數(shù)sColor。最后一行代碼刪除了對(duì)ClassA的引用,這樣以后就不能再調(diào)用它。
所有的新屬性和新方法都必須刪除了新方法的代碼行后定義。否則,可能會(huì)覆蓋超類的相關(guān)屬性和方法:
function ClassB(sColor,sName){
this.newMethod=classA;
this.newMethod(sColor);
delete this.newMethod;
this.name=sName;
this.sayName=function(){
alert(this.name);
};
}
運(yùn)行下面的例子:
var objA=new ClassA("red");
var objB=new ClassB("blue","Nicholas");
objA.sayColor();//outputs "red"
objB.sayColor();//outputs "blue"
objB.sayName(); //outputs "Nicholas"
例如,如果存在兩個(gè)類ClassX和ClassY,ClassZ想繼承這兩個(gè)類,可以使用下面的代碼:
function ClassZ(){
this.newMethod=ClassX;
this.newMethod();
delete this.newMethod;
this.newMethod=ClassY;
this.newMethod();
delete this.newMethod;
}
這里存在一個(gè)弊端,如果ClassX和ClassY具有同名的屬性或方法,ClassY具有高優(yōu)先級(jí),因?yàn)樗鼜暮竺胬^承。除了這一點(diǎn)小問(wèn)題外,用對(duì)象冒充實(shí)現(xiàn)多繼承機(jī)制輕而易舉。
由于這種繼承方式的流行,ECMAScript的第三版為Function對(duì)象加入了兩個(gè)新方法,即call()和apply()。
2.call()方法
call()方法與經(jīng)典的對(duì)象冒充方法最相似的方法。它的第一個(gè)參數(shù)用作this的對(duì)象。其他參數(shù)都直接傳遞給函數(shù)自身。例如:
function sayColor(sPrefix,sSuffix){
alert(sPrefix+this.color+sSuffix);
};
var obj=new Object();
obj.color="red";
//outputs "The color is red,a very nice color indeed."
sayColor.call(obj,"The color is ",", a very nice color indeed.")
在這個(gè)例子中,函數(shù)sayColor()在對(duì)象外定義,即使它不屬于任何對(duì)象,也可以引用關(guān)鍵字this。對(duì)象的obj的color屬性等于"red"。調(diào)用call()方法時(shí),第一個(gè)參數(shù)是obj,說(shuō)明
應(yīng)該賦予sayColor()函數(shù)中的this關(guān)鍵字的值是obj。第二個(gè)和第三個(gè)參數(shù)是字符串。它們與sayColor()函數(shù)中的參數(shù)prefix和suffix匹配,最后生成消息"The color is red, a very nice color indeed."
要與繼承機(jī)制的對(duì)象冒充方法一起使用該方法,只需將前三行的賦值、調(diào)用和刪除代碼替換即可:
function ClassB(sColor,sName){
//this.newMethod=classA;
//this.newMethod(sColor);
//delete this.newMethod;
Class.call(this,sColor);
this.name=sName;
this.sayName=function(){
alert(this.name);
};
}
這里,想讓ClassA中的關(guān)鍵字this等于新創(chuàng)建的ClassB對(duì)象,因此this是第一個(gè)參數(shù)。第二個(gè)參數(shù)sColor對(duì)兩個(gè)類來(lái)說(shuō)都是唯一的參數(shù)。
3.apply()方法
apply()方法有兩個(gè)參數(shù),用作this的對(duì)象和要傳遞給函數(shù)的參數(shù)和數(shù)組。例如:
function sayColor(sPrefix,sSuffix){
alert(sPrefix+this.color+sSuffix);
};
var obj=new Object();
obj.color="red";
//outputs "The Color is red,a very nice color indeed."
sayColor.apply(obj,new Array("The Color is ",",a very nice color indeed."));
這個(gè)例子與前面的例子相同,只是現(xiàn)在調(diào)用的是apply()方法。調(diào)用apply()方法時(shí),第一個(gè)參數(shù)仍是obj,說(shuō)明應(yīng)該賦予sayColor()中的this關(guān)鍵字值是obj。第二個(gè)參數(shù)是由兩個(gè)字符串組成的數(shù)組,與sayColor()的參數(shù)prefix和suffix匹配。生成的消息仍是
"The Color is red,a nice color indeed."
該方法也用于替換前三行的賦值、調(diào)用和刪除新方法的代碼:
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);
};
}
同樣的,第一個(gè)參數(shù)仍是this。第二個(gè)參數(shù)是只有一個(gè)值color的數(shù)組。可以把ClassB的整個(gè)arguments對(duì)象作為第二個(gè)參數(shù)傳遞給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);
};
}
當(dāng)然,只有超類中的參數(shù)順序與子類中的參數(shù)順序完全一致時(shí)才可以傳遞參數(shù)對(duì)象。如果不是,就必須創(chuàng)建一個(gè)單獨(dú)的數(shù)組,按照正確的順序放置參數(shù)。此外,還可以使用call()方法。
原理:構(gòu)造函數(shù)使用this關(guān)鍵字給所有屬性和方法賦值(即采用類聲明的構(gòu)造函數(shù)方式)。
因?yàn)闃?gòu)造函數(shù)只是一個(gè)函數(shù),所以可使ClassA的構(gòu)造函數(shù)成為ClassB的方法,然后調(diào)用它。ClassB就會(huì)收到ClassA的構(gòu)造函數(shù)中定義的屬性和方法。
例如:
下面方式定義的ClassA和ClassB:
復(fù)制代碼 代碼如下:
function ClassA(sColor){
this.color=sColor;
this.sayColor=function(){
alert(this.color);
};
}
function ClassB(sColor){
}
關(guān)鍵字this引用的是構(gòu)造函數(shù)當(dāng)前創(chuàng)建的對(duì)象。
不過(guò)在這個(gè)方法中國(guó),this指向的是所屬的對(duì)象。這個(gè)原理把ClassA作為常規(guī)函數(shù)來(lái)建立繼承機(jī)制,而不是作為構(gòu)造行數(shù)。
如下使用構(gòu)造函數(shù)ClassB可以實(shí)現(xiàn)繼承機(jī)制:
復(fù)制代碼 代碼如下:
function ClassB(sColor){
this.newMethod=ClassA;
this.newMethod(sColor);
delete this.newMethod;
}
這段代碼中,為(但我覺得這里應(yīng)該是"把")ClassA賦予了方法newMethod(記住函數(shù)名只是指向它的指針)。然后調(diào)用該方法,傳遞給它的是ClassB的構(gòu)造函數(shù)的參數(shù)sColor。最后一行代碼刪除了對(duì)ClassA的引用,這樣以后就不能再調(diào)用它。
所有的新屬性和新方法都必須刪除了新方法的代碼行后定義。否則,可能會(huì)覆蓋超類的相關(guān)屬性和方法:
復(fù)制代碼 代碼如下:
function ClassB(sColor,sName){
this.newMethod=classA;
this.newMethod(sColor);
delete this.newMethod;
this.name=sName;
this.sayName=function(){
alert(this.name);
};
}
運(yùn)行下面的例子:
復(fù)制代碼 代碼如下:
var objA=new ClassA("red");
var objB=new ClassB("blue","Nicholas");
objA.sayColor();//outputs "red"
objB.sayColor();//outputs "blue"
objB.sayName(); //outputs "Nicholas"
例如,如果存在兩個(gè)類ClassX和ClassY,ClassZ想繼承這兩個(gè)類,可以使用下面的代碼:
復(fù)制代碼 代碼如下:
function ClassZ(){
this.newMethod=ClassX;
this.newMethod();
delete this.newMethod;
this.newMethod=ClassY;
this.newMethod();
delete this.newMethod;
}
這里存在一個(gè)弊端,如果ClassX和ClassY具有同名的屬性或方法,ClassY具有高優(yōu)先級(jí),因?yàn)樗鼜暮竺胬^承。除了這一點(diǎn)小問(wèn)題外,用對(duì)象冒充實(shí)現(xiàn)多繼承機(jī)制輕而易舉。
由于這種繼承方式的流行,ECMAScript的第三版為Function對(duì)象加入了兩個(gè)新方法,即call()和apply()。
2.call()方法
call()方法與經(jīng)典的對(duì)象冒充方法最相似的方法。它的第一個(gè)參數(shù)用作this的對(duì)象。其他參數(shù)都直接傳遞給函數(shù)自身。例如:
復(fù)制代碼 代碼如下:
function sayColor(sPrefix,sSuffix){
alert(sPrefix+this.color+sSuffix);
};
var obj=new Object();
obj.color="red";
//outputs "The color is red,a very nice color indeed."
sayColor.call(obj,"The color is ",", a very nice color indeed.")
在這個(gè)例子中,函數(shù)sayColor()在對(duì)象外定義,即使它不屬于任何對(duì)象,也可以引用關(guān)鍵字this。對(duì)象的obj的color屬性等于"red"。調(diào)用call()方法時(shí),第一個(gè)參數(shù)是obj,說(shuō)明
應(yīng)該賦予sayColor()函數(shù)中的this關(guān)鍵字的值是obj。第二個(gè)和第三個(gè)參數(shù)是字符串。它們與sayColor()函數(shù)中的參數(shù)prefix和suffix匹配,最后生成消息"The color is red, a very nice color indeed."
要與繼承機(jī)制的對(duì)象冒充方法一起使用該方法,只需將前三行的賦值、調(diào)用和刪除代碼替換即可:
復(fù)制代碼 代碼如下:
function ClassB(sColor,sName){
//this.newMethod=classA;
//this.newMethod(sColor);
//delete this.newMethod;
Class.call(this,sColor);
this.name=sName;
this.sayName=function(){
alert(this.name);
};
}
這里,想讓ClassA中的關(guān)鍵字this等于新創(chuàng)建的ClassB對(duì)象,因此this是第一個(gè)參數(shù)。第二個(gè)參數(shù)sColor對(duì)兩個(gè)類來(lái)說(shuō)都是唯一的參數(shù)。
3.apply()方法
apply()方法有兩個(gè)參數(shù),用作this的對(duì)象和要傳遞給函數(shù)的參數(shù)和數(shù)組。例如:
復(fù)制代碼 代碼如下:
function sayColor(sPrefix,sSuffix){
alert(sPrefix+this.color+sSuffix);
};
var obj=new Object();
obj.color="red";
//outputs "The Color is red,a very nice color indeed."
sayColor.apply(obj,new Array("The Color is ",",a very nice color indeed."));
這個(gè)例子與前面的例子相同,只是現(xiàn)在調(diào)用的是apply()方法。調(diào)用apply()方法時(shí),第一個(gè)參數(shù)仍是obj,說(shuō)明應(yīng)該賦予sayColor()中的this關(guān)鍵字值是obj。第二個(gè)參數(shù)是由兩個(gè)字符串組成的數(shù)組,與sayColor()的參數(shù)prefix和suffix匹配。生成的消息仍是
"The Color is red,a nice color indeed."
該方法也用于替換前三行的賦值、調(diào)用和刪除新方法的代碼:
復(fù)制代碼 代碼如下:
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);
};
}
同樣的,第一個(gè)參數(shù)仍是this。第二個(gè)參數(shù)是只有一個(gè)值color的數(shù)組。可以把ClassB的整個(gè)arguments對(duì)象作為第二個(gè)參數(shù)傳遞給apply()方法:
復(fù)制代碼 代碼如下:
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);
};
}
當(dāng)然,只有超類中的參數(shù)順序與子類中的參數(shù)順序完全一致時(shí)才可以傳遞參數(shù)對(duì)象。如果不是,就必須創(chuàng)建一個(gè)單獨(dú)的數(shù)組,按照正確的順序放置參數(shù)。此外,還可以使用call()方法。
您可能感興趣的文章:
- Javascript 繼承機(jī)制的實(shí)現(xiàn)
- javascript類繼承機(jī)制的原理分析
- 基于JavaScript實(shí)現(xiàn)繼承機(jī)制之原型鏈(prototype chaining)的詳解
- Javascript繼承機(jī)制的設(shè)計(jì)思想分享
- 由JavaScript中call()方法引發(fā)的對(duì)面向?qū)ο罄^承機(jī)制call的思考
- 基于JavaScript實(shí)現(xiàn)繼承機(jī)制之調(diào)用call()與apply()的方法詳解
- 基于JavaScript實(shí)現(xiàn)繼承機(jī)制之構(gòu)造函數(shù)+原型鏈混合方式的使用詳解
- Javascript繼承機(jī)制詳解
相關(guān)文章
JavaScript 對(duì)象鏈?zhǔn)讲僮鳒y(cè)試代碼
自從使用了jQuery以后,對(duì)它的鏈?zhǔn)讲僮骱苁且蕾嚕灾劣诔3SX得其他庫(kù)不好用。。
2010-04-04
編寫可維護(hù)面向?qū)ο蟮腏avaScript代碼[翻譯]
編寫可維護(hù)面向?qū)ο蟮腏avaScript代碼[翻譯],學(xué)習(xí)js面向?qū)ο缶帉懙呐笥芽梢詤⒖枷隆?/div> 2011-02-02
javascript 面向?qū)ο缶幊袒A(chǔ):封裝
“在面向?qū)ο蟮乃枷胫?,最核心的概念之一就是類。一個(gè)類表示了具有相似性質(zhì)的一類事物的抽象,通過(guò)實(shí)例化一個(gè)類,可以獲得屬于該類的一個(gè)實(shí)例(即對(duì)象)”。
2009-08-08
JavaScript對(duì)象鏈?zhǔn)讲僮鞔a(jquery)
自從使用了jQuery以后,對(duì)它的鏈?zhǔn)讲僮骱苁且蕾?,以至于常常覺得其他庫(kù)不好用。。
2010-07-07
javascript 面向?qū)ο缶幊袒A(chǔ) 多態(tài)
javascript 面向?qū)ο缶幊袒A(chǔ) 多態(tài) 的實(shí)現(xiàn)方法說(shuō)明,大家可以看下下面的代碼。
2009-08-08
javascript 面向?qū)ο蟮慕?jīng)典實(shí)例代碼
這里的面向?qū)ο笾饕鞘褂胮rototype屬性,大家可以參考下。
2009-12-12
收集的幾個(gè)不錯(cuò)的javascript類小例子
自己比較喜歡javascript類,主要是方便擴(kuò)展。
2007-12-12 
