摻元類就是共享通用的方法和屬性,將差異比較大的類中相同功能的方法集中到一個類中聲明,這樣需要這些方法的類就可以直接從摻元類中進行擴展,通用的方法只需要聲明一遍就行了。從代碼的大小、質量方面來說,這還是有一定效益的。如圖4.7所示,摻元類就是讓一個類被多個類繼承,這種繼承關係被形象地稱為多親繼承,它是一種比較特殊的類形式。
圖 4.7 多親繼承示意圖如果希望某個函數被多個類調用,那麼可以通過擴充的方式讓這些類共享該函數。具體的設計思路:先創建包含通用函數的超類,然後利用這個超類擴充子類,這種包含通用方法的類可以稱為摻元類。例如,先設計一個摻元類F,設想兩個子類A和B能夠繼承摻元類F的通用方法getx和gety。代碼如下:
var F=function(x,y){//構造函數F,摻元類
this.x=x;
this.y=y;
}
F.prototype={
getx:function{
return this.x;
},
gety:function(y){
return this.y;
}
}
然後,定義兩個子類A和B,利用類繼承方法先繼承摻元類中的本地屬性,以方便繼承的方法正確獲取值。實際應用中不使用類繼承來繼承摻元類的本地屬性和方法。
A=function(x,y){//子類A
F.call(this,x,y);//繼承摻元類F
};
B=function(x,y){//子類B
F.call(this,x,y);//繼承摻元類F
};
要讓A類和B類都繼承F類,可以使用原型繼承方法來實現,但原型繼承需要實例化F類。我們可以模仿複製繼承方法設計一個專門函數來實現這種繼承關係,具體代碼如下:
//摻元類繼承封裝函數,其中參數Sub表示子類,參數Sup表示摻元類
function extend(Sub,Sup){
for(m in Sup.prototype){//遍歷摻元類的原型對像
if(!Sub.prototype[m]){//如果子類不存在同名成員,則複製摻元類原型成員給子類原型對像
Sub.prototype[m]=Sup.prototype[m];
}
}
}
該函數很簡單,使用for in循環遍歷摻元類的原型對像中的每一個成員,並將其添加到子類的原型對像中。如果子類中已存在同名成員,則跳過該成員,轉而處理下一個,這樣能夠確保子類原型對像中的成員不會被改寫。有了這個封裝函數,就可以直接調用它來快速生成多個相同的子類。傳遞子類參數必須事先聲明,並且應通過類繼承方法來繼承F的本地屬性和方法。
extend(A,F);//繼承F的子類A
extend(B,F);//繼承F的子類B
最後,實例化A類和B類,這樣就可以調用F定義的通用方法了。
var a=new A(1,2);
var b=new B(10,20);
alert(a.getx);//1
alert(a.gety);//2
alert(b.getx);//10
alert(b.gety);//20
也可以把多個子類合併到一個類中來實現多重繼承。例如,下面的示例定義了兩個類A和B,並分別為它們定義兩個原型方法。
var A=function{}//類A
A.prototype={
x:function{
return"x";
}
}
var B=function{}//類B
B.prototype={
y:function{
return"y";
}
}
C=function{};//空類C
extend(C,A);//把類A繼承給類C
extend(C,B);//把類B繼承給類C
var c=new C;//實例化類C
alert(c.x)//字符x
alert(c.y)//字符y
面向對像中並不是所有的事物泛型都是使用繼承關係來描述的,繼承關係只是泛型關係的一種,除此之外,創建關係、原型關係、聚合關係、組合關係等,都是泛型的一種類型。泛型概念很寬泛,通常使用繼承、聚合和組合來描述事物的名詞特性,而使用原型、元類等其他概念來描述事物的形容詞概念。