幾乎每位在開發Javascript時嘗試應用面向對象技術的開發者,或多或少都會問自己一個問題:“如何調用父類(super class)的方法?”在AJax技術還沒有目前這樣炙手可熱之前,這種問題很少出現,因為大多數開發者僅在進行客戶端form驗證或者簡單的DHtml/DOM操作時使用JavaScript。在那些簡單的解決方案中,函數式編程(functional programming)是很有意義的,面向對象編程則處在次之重要的位置。
現在,AJax技術發展勢頭迅猛,開發者已經建立了一個調用大量客戶端JavaScript、不斷增長的、復雜的系統。因此,在Javascript上嘗試OO技術便成為了管理復雜性的一種手段。在此過程中,多數開發者很快便認識到:JavaScript是一種原型化的(prototypical)語言,它缺少OO自身帶來的多種便利。
OO設計的主旨和關於它的一些話題談起來很大,但只著眼於Class的定義方式,我認為它是JavaScript開發者嘗試解決問題的首選。因此,你可以在互聯網上找到許多不同的問題解決案例,但在我看過它們後不免有些失望——這些案例都是在某個場合下適用,而不是放之四海而皆准的通法。而我對這個話題的興趣來自於我的team在開發 ThinWire AJax Framework 的影響。
由於這個框架生成出對客戶端代碼的需求,才使我們“被迫”去實現可靠的、支持父類方法調用的OO模式。通過父類調用,你可以進一步依靠類的繼承特性來核心化通用代碼,從而更易於減少重復代碼,去掉客戶端代碼的壞味道。
下面羅列出了一些在我的研究過程中遇到的解決方式。最終,我沒有從中找出一個可以接收的解決方案,於是我不得不實現一個自己的解決方案,你將在本文的結尾部分看到這個方案。
然而父類調用在這裡是最重要的OO機制,因此我需要一個相應的工作模式,也正是因為在我的觀點中原型化方式是丑陋的,所以我更需要一種更加自然地使用JavaScript定義類的方法。
More Solutions:
好吧,讓我們進入討論。正如開發者所察覺的那樣,在JS中實現基本的繼承是很容易的事,事實上有一些眾所周知的方法:
丑陋的Solution:
沒有進行父類調用的簡單繼承:
// 提前寫好的JavaScript Class定義和繼承
// 當然,這種代碼很丑陋,散發著代碼的壞味道。
function BaseClass() {
//BaseClass constructor code goes here
}
BaseClass.prototype.getName = function() {
return "BaseClass";
}
function SubClass() {
//SubClass constructor code goes here
}
//Inherit the methods of BaseClass
SubClass.prototype = new BaseClass();
//Override the parent's getName method
SubClass.prototype.getName = function() {
return "SubClass";
}
//Alerts "SubClass"
alert(new SubClass().getName());
導致 IE內存洩露 的Solution:
這種實現方式能夠導致在IE中的內存洩漏,你應該盡量避免:
// 運行時的JavaScript Class 定義和繼承
// 看上去很傳統,但這些腳本會導致在Internet Explorer中的內存洩漏.
function BaseClass() {
this.getName = function() {
return "BaseClass";
};
//BaseClass constructor code goes here
}
function SubClass() {
//在對象實例建立時重載父類的getName方法
this.getName = function() {
return "SubClass";
}
//SubClass constructor code goes here
}
//Inherit the methods of BaseClass
SubClass.prototype = new BaseClass();
//Alerts "SubClass"
alert(new SubClass().getName());
就像我在第一個實現方法中所注釋的那樣,第一個實現方法有些丑陋,但它相比引起內存洩漏的第二種方式便是首選了。
我把這兩種方法放在這裡的目的是指出你不應該使用它們。