用JavaScript實(shí)現(xiàn)單繼承和多繼承的簡(jiǎn)單方法
更新時(shí)間:2009年03月29日 12:33:26 作者:
JavaScript是一種強(qiáng)大的多泛型編程語(yǔ)言,其融合了面向過(guò)程、面向?qū)ο蠛秃瘮?shù)式編程于一身,具備強(qiáng)大的表現(xiàn)能力。
JavaScript就其本質(zhì)是函數(shù)式編程語(yǔ)言,是Lisp的后代,同時(shí)又加入了一下面向?qū)ο缶幊痰脑?,放棄了一些難懂的函數(shù)式語(yǔ)言的元素。
函數(shù)式編程語(yǔ)言可以實(shí)現(xiàn)面向?qū)ο缶幊?,這是毫無(wú)疑義的,Curry方法可以實(shí)現(xiàn)對(duì)類和對(duì)象的模擬。但是JavaScript提供了另一種實(shí)現(xiàn)OOP的方法:原型繼承。
因此,JavaScript實(shí)現(xiàn)面向?qū)ο缶幊毯鸵话愕暮瘮?shù)式編程語(yǔ)言還是有所區(qū)別的。
本文我將會(huì)給大家介紹JavaScript實(shí)現(xiàn)單繼承和多繼承的方法。
用原型實(shí)現(xiàn)單繼承:
有很多JavaScript庫(kù)提供了一些函數(shù)幫助實(shí)現(xiàn)單繼承。但實(shí)際上,JavaScript本身就提供了原型繼承的方法。因此,根本不需要提供特定的方法來(lái)實(shí)現(xiàn),簡(jiǎn)單使用JavaScript代碼就可以實(shí)現(xiàn)單繼承。
但是,JavaScript提供的原型繼承方法很容易犯錯(cuò),下面我給大家演示一下怎樣簡(jiǎn)潔明了地實(shí)現(xiàn)原型繼承。
假設(shè)MyB繼承MyA類,那么,代碼如下:
function MyA(){
if(MyA.prototype.baseClass!==undefined){
MyA.prototype.baseClass.call(this);
}
……一般代碼
}
function MyB(){
if(MyB.prototype.baseClass!==undefined){
MyB.prototype.baseClass.call(this);
}
……一般代碼
}
MyB.prototype=new MyA();
MyB.prototype.baseClass=MyB.prototype.constructor;//使用baseClass引用//基類的構(gòu)造器函數(shù)。
MyB.prototype.constructor=MyB;//恢復(fù)子類的構(gòu)造器屬性 用于未來(lái)通過(guò)這個(gè)屬性判//斷對(duì)象的類型。
var myA=new MyA();
var myB=new MyB();
上述javascript代碼中,我在每一個(gè)構(gòu)造函數(shù)中都添加了這么一段代碼:
if(ClassName.prototype.baseClass!==undefined){
ClassName.prototype.baseClass.call(this);
}
這段代碼尋找原型中的baseClass方法,如果有,就調(diào)用它。
在后面的原型繼承的實(shí)現(xiàn)中,我為子類創(chuàng)建了baseClass屬性,它的值是基類的構(gòu)造函數(shù)。因此,只要遵守我的方式編寫(xiě)代碼,就可以保證基類的構(gòu)造函數(shù)在子類構(gòu)造實(shí)例時(shí)會(huì)得到執(zhí)行。
現(xiàn)在,如果MyA類又繼承了Base類,只需要添加3行原型繼承代碼即可:
MyA.prototype=new Base();
MyA.prototype.baseClass= MyA.prototype.constructor;//使用baseClass引用//基類的構(gòu)造器函數(shù)。
MyA.prototype.constructor= MyA;//恢復(fù)子類的構(gòu)造器屬性 用于未來(lái)通過(guò)這個(gè)屬性判//斷對(duì)象的類型。
不需要修改MyA類本身的代碼,MyA類及其子類MyB類的實(shí)例就都可以得到正確的執(zhí)行。
那些JavaScript庫(kù)實(shí)現(xiàn)的繼承,需要修改Object,Function等基類,容易引起沖突。還有一些方法,每一次實(shí)現(xiàn)繼承,都必須手工修改子類的構(gòu)造函數(shù),以使構(gòu)造函數(shù)能夠正確調(diào)用基類的構(gòu)造函數(shù)。
上面提供的方法編寫(xiě)JavaScript代碼很好地解決了這些問(wèn)題。
用Mixin(混入)實(shí)現(xiàn)多繼承
JavaScript本身并沒(méi)有提供多繼承的機(jī)制,但我們可以使用Mixin(混入)這種技巧實(shí)現(xiàn)多繼承的效果。
下面是我編寫(xiě)的Mixin助手方法,可以為類和對(duì)象動(dòng)態(tài)添加屬性。
1,copyClassPrototypeProperties復(fù)制類的原型屬性
/**
* 把源類原型上的所有屬性復(fù)制到目標(biāo)對(duì)象上,第一個(gè)參數(shù)是boolean值,表示是否覆蓋目標(biāo)類的原型的屬性
*/
function copyClassPrototypeProperties(isOverride,receivingClass,givingClass){
if(arguments.length>3){
for(var i=3;i<arguments.length;i++){
receivingClass.prototype[arguments[i]]=givingClass.prototype[arguments[i]];
}
}else if(arguments.length==3){
for(var name in givingClass.prototype){
if(isOverride){
receivingClass.prototype[name]=givingClass.prototype[name];
}else{
//不覆蓋
if(!receivingClass.prototype[name]){
receivingClass.prototype[name]=givingClass.prototype[name];
}
}
}
}else{
throw "Please give 3 arguments at least!";
}
}
2,copyObjectProperties復(fù)制對(duì)象的屬性
/*
* 把源對(duì)象的所有屬性復(fù)制到目標(biāo)對(duì)象上,第一個(gè)參數(shù)是boolean值,表示是否覆蓋目標(biāo)對(duì)象的屬性
*/
function copyObjectProperties(isOverride,receivingObject,givingObject){
if(arguments.length>3){
for(var i=3;i<arguments.length;i++){
receivingObject[arguments[i]]=givingObject[arguments[i]];
}
}else if(arguments.length==3){
for(var name in givingObject){
if(isOverride){
receivingObject[name]=givingObject[name];
}else{
//不覆蓋
if(!receivingObject[name]){
receivingObject[name]=givingObject[name];
}
}
}
}else{
throw "Please give 3 arguments at least!";
}
}
3,copyProperties復(fù)制屬性到對(duì)象
/*
* 把屬性復(fù)制到目標(biāo)對(duì)象中,屬性可以有任意多個(gè),并且可以是數(shù)組。
*/
function copyProperties(target){
for (var i=1;i<arguments.length;i++){
if(arguments[i].constructor===Array){
copyArrayProperties(target,arguments[i]);
}else{
for(var name in arguments[i]){
target[name] =arguments[i][name];
}
}
}
}
/*
* 把數(shù)組格式的屬性復(fù)制到目標(biāo)對(duì)象中,用戶不應(yīng)該直接調(diào)用這個(gè)方法
*/
function copyArrayProperties(target,arrayArg){
for(var i=0;i<arrayArg.length;i++){
if(arrayArg[i].constructor===Array){
copyArrayProperties(target,arrayArg[i]);
}else{
for(var name in arrayArg[i]){
target[name] =arrayArg[i][name];
}
}
}
}
PS:目前我正打算寫(xiě)一個(gè)JavaScript庫(kù),用簡(jiǎn)潔的代碼提供很多功能,包括UI組件。
函數(shù)式編程語(yǔ)言可以實(shí)現(xiàn)面向?qū)ο缶幊?,這是毫無(wú)疑義的,Curry方法可以實(shí)現(xiàn)對(duì)類和對(duì)象的模擬。但是JavaScript提供了另一種實(shí)現(xiàn)OOP的方法:原型繼承。
因此,JavaScript實(shí)現(xiàn)面向?qū)ο缶幊毯鸵话愕暮瘮?shù)式編程語(yǔ)言還是有所區(qū)別的。
本文我將會(huì)給大家介紹JavaScript實(shí)現(xiàn)單繼承和多繼承的方法。
用原型實(shí)現(xiàn)單繼承:
有很多JavaScript庫(kù)提供了一些函數(shù)幫助實(shí)現(xiàn)單繼承。但實(shí)際上,JavaScript本身就提供了原型繼承的方法。因此,根本不需要提供特定的方法來(lái)實(shí)現(xiàn),簡(jiǎn)單使用JavaScript代碼就可以實(shí)現(xiàn)單繼承。
但是,JavaScript提供的原型繼承方法很容易犯錯(cuò),下面我給大家演示一下怎樣簡(jiǎn)潔明了地實(shí)現(xiàn)原型繼承。
假設(shè)MyB繼承MyA類,那么,代碼如下:
function MyA(){
if(MyA.prototype.baseClass!==undefined){
MyA.prototype.baseClass.call(this);
}
……一般代碼
}
function MyB(){
if(MyB.prototype.baseClass!==undefined){
MyB.prototype.baseClass.call(this);
}
……一般代碼
}
MyB.prototype=new MyA();
MyB.prototype.baseClass=MyB.prototype.constructor;//使用baseClass引用//基類的構(gòu)造器函數(shù)。
MyB.prototype.constructor=MyB;//恢復(fù)子類的構(gòu)造器屬性 用于未來(lái)通過(guò)這個(gè)屬性判//斷對(duì)象的類型。
var myA=new MyA();
var myB=new MyB();
上述javascript代碼中,我在每一個(gè)構(gòu)造函數(shù)中都添加了這么一段代碼:
if(ClassName.prototype.baseClass!==undefined){
ClassName.prototype.baseClass.call(this);
}
這段代碼尋找原型中的baseClass方法,如果有,就調(diào)用它。
在后面的原型繼承的實(shí)現(xiàn)中,我為子類創(chuàng)建了baseClass屬性,它的值是基類的構(gòu)造函數(shù)。因此,只要遵守我的方式編寫(xiě)代碼,就可以保證基類的構(gòu)造函數(shù)在子類構(gòu)造實(shí)例時(shí)會(huì)得到執(zhí)行。
現(xiàn)在,如果MyA類又繼承了Base類,只需要添加3行原型繼承代碼即可:
MyA.prototype=new Base();
MyA.prototype.baseClass= MyA.prototype.constructor;//使用baseClass引用//基類的構(gòu)造器函數(shù)。
MyA.prototype.constructor= MyA;//恢復(fù)子類的構(gòu)造器屬性 用于未來(lái)通過(guò)這個(gè)屬性判//斷對(duì)象的類型。
不需要修改MyA類本身的代碼,MyA類及其子類MyB類的實(shí)例就都可以得到正確的執(zhí)行。
那些JavaScript庫(kù)實(shí)現(xiàn)的繼承,需要修改Object,Function等基類,容易引起沖突。還有一些方法,每一次實(shí)現(xiàn)繼承,都必須手工修改子類的構(gòu)造函數(shù),以使構(gòu)造函數(shù)能夠正確調(diào)用基類的構(gòu)造函數(shù)。
上面提供的方法編寫(xiě)JavaScript代碼很好地解決了這些問(wèn)題。
用Mixin(混入)實(shí)現(xiàn)多繼承
JavaScript本身并沒(méi)有提供多繼承的機(jī)制,但我們可以使用Mixin(混入)這種技巧實(shí)現(xiàn)多繼承的效果。
下面是我編寫(xiě)的Mixin助手方法,可以為類和對(duì)象動(dòng)態(tài)添加屬性。
1,copyClassPrototypeProperties復(fù)制類的原型屬性
/**
* 把源類原型上的所有屬性復(fù)制到目標(biāo)對(duì)象上,第一個(gè)參數(shù)是boolean值,表示是否覆蓋目標(biāo)類的原型的屬性
*/
function copyClassPrototypeProperties(isOverride,receivingClass,givingClass){
if(arguments.length>3){
for(var i=3;i<arguments.length;i++){
receivingClass.prototype[arguments[i]]=givingClass.prototype[arguments[i]];
}
}else if(arguments.length==3){
for(var name in givingClass.prototype){
if(isOverride){
receivingClass.prototype[name]=givingClass.prototype[name];
}else{
//不覆蓋
if(!receivingClass.prototype[name]){
receivingClass.prototype[name]=givingClass.prototype[name];
}
}
}
}else{
throw "Please give 3 arguments at least!";
}
}
2,copyObjectProperties復(fù)制對(duì)象的屬性
/*
* 把源對(duì)象的所有屬性復(fù)制到目標(biāo)對(duì)象上,第一個(gè)參數(shù)是boolean值,表示是否覆蓋目標(biāo)對(duì)象的屬性
*/
function copyObjectProperties(isOverride,receivingObject,givingObject){
if(arguments.length>3){
for(var i=3;i<arguments.length;i++){
receivingObject[arguments[i]]=givingObject[arguments[i]];
}
}else if(arguments.length==3){
for(var name in givingObject){
if(isOverride){
receivingObject[name]=givingObject[name];
}else{
//不覆蓋
if(!receivingObject[name]){
receivingObject[name]=givingObject[name];
}
}
}
}else{
throw "Please give 3 arguments at least!";
}
}
3,copyProperties復(fù)制屬性到對(duì)象
/*
* 把屬性復(fù)制到目標(biāo)對(duì)象中,屬性可以有任意多個(gè),并且可以是數(shù)組。
*/
function copyProperties(target){
for (var i=1;i<arguments.length;i++){
if(arguments[i].constructor===Array){
copyArrayProperties(target,arguments[i]);
}else{
for(var name in arguments[i]){
target[name] =arguments[i][name];
}
}
}
}
/*
* 把數(shù)組格式的屬性復(fù)制到目標(biāo)對(duì)象中,用戶不應(yīng)該直接調(diào)用這個(gè)方法
*/
function copyArrayProperties(target,arrayArg){
for(var i=0;i<arrayArg.length;i++){
if(arrayArg[i].constructor===Array){
copyArrayProperties(target,arrayArg[i]);
}else{
for(var name in arrayArg[i]){
target[name] =arrayArg[i][name];
}
}
}
}
PS:目前我正打算寫(xiě)一個(gè)JavaScript庫(kù),用簡(jiǎn)潔的代碼提供很多功能,包括UI組件。
相關(guān)文章
javascript 面向?qū)ο缶幊袒A(chǔ) 多態(tài)
javascript 面向?qū)ο缶幊袒A(chǔ) 多態(tài) 的實(shí)現(xiàn)方法說(shuō)明,大家可以看下下面的代碼。2009-08-08javascript 面向?qū)ο笕吕砭氈當(dāng)?shù)據(jù)的封裝
JavaScript 是一種非常靈活的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言,它與傳統(tǒng)的強(qiáng)類型的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言(如 C++,Java,C# 等)有很大不同,所以要實(shí)現(xiàn)如 C++、java、C# 當(dāng)中的一些特性就需要換一種思考方式來(lái)解決。2009-12-12javascript 面向?qū)ο蟮慕?jīng)典實(shí)例代碼
這里的面向?qū)ο笾饕鞘褂胮rototype屬性,大家可以參考下。2009-12-12XRegExp 0.2: Now With Named Capture
XRegExp 0.2: Now With Named Capture...2007-11-11javascript 面向?qū)ο蟮腏avaScript類
這一節(jié)來(lái)說(shuō)下緊接著的一個(gè)概念——類。雖然JavaScript中沒(méi)有class關(guān)鍵字,但作為開(kāi)發(fā)人員我們一定要有這個(gè)思想。在C#中類可以分為實(shí)例類和靜態(tài)類,JavaScript亦然。2010-05-05javascript 面向?qū)ο?實(shí)現(xiàn)namespace,class,繼承,重載
這幾天老大天天嚷嚷要重構(gòu)我們寫(xiě)的javascript,抱怨代碼太混亂,可讀性差,維護(hù)困難,要求javascript也按面對(duì)象的模型來(lái)重構(gòu)。2009-10-10

JavaScript中使用構(gòu)造函數(shù)實(shí)現(xiàn)繼承的代碼
JavaScript中借用構(gòu)造函數(shù)實(shí)現(xiàn)繼承的代碼,需要的朋友可以參考下。
2010-08-08