從這些方案中,應該能提煉出一個具有其思想內涵的框架,該框架須具有簡單、可重用、易于理解并無依賴等特點,其中簡單性與可用性是重點。以下是使用示例:
有幾點需要留意:
對結果相當滿意:使類的定義結構化,保持單一繼承,并且能夠調用超類方法。
簡單的類創建與繼承
下面為其實現(便于閱讀并有注釋),大概25行左右。歡迎并感謝提出建議。
其中 “初始化(initializing/don't call init)”與“創建_super方法”最為棘手。接下來,我會對此做簡要的介紹,使得大家對其實現機制能更好的理解。
初始化
為了說明函數原型式的繼承方式,首先來看傳統的實現過程,即將子類的prototype屬性指向父類的一個實例。如下所示:
然而,這里具有挑戰性的一點,便是我們只想要得到‘是否實例(instatnceOf)'的效果,而不需要實例一個 Person并調用其構造函數所帶來的后果。為防止這一點,在代碼中設置一個bool參數initializing,只有在實例化父類并將其配置到子類的prototype屬性時, 其值才為true。這樣處理的目的是區分開真正的實例化與設計繼承時這兩種調用構造函數之間的區別,進而在真正實例化時調用init方法:
值得特別注意的是,因為在init函數中可能會運行相當費資源的代碼(如連接服務器,創建DOM元素等,誰也無法預測),所以做出區分是完全必要的。
超類方法(Super Method)
當使用繼承時,最常見的需求便是子類能訪問超類被覆寫的方法。在該實現下,最終的方案便是提供一個臨時方法(._super),該方法指向超類方法,并且只能在子類方法中訪問。
實現這一功能需要幾步處理。首先,我們使用extend來合并基本的Person實例(類實例,上面我們提到過其構造過程)與字面對象(Person.extend()的函數參數)。在合并過程中,做了簡單的檢查:首先檢查將被合并的的屬性是否為函數,如為函數,然后檢查將被覆寫的超類屬性是否也為函數?如果這兩個檢查都為true,則需要為該屬性準備_super方法。
注意,在這里創建了一個匿名閉包(返回的是函數對象)來封裝增加的super方法。基于維護運行環境的需要,我們應該將舊的this._super(不管其是否存在)保存起來以備函數運行后重置,這有助于在有相同名稱(不想偶然丟失對象指針)的情況下發生不可預知的問題。
然后,創建新的_super方法,該方法對象僅指向超類中被覆寫的方法。謝天謝地,不用對_super做任何改動或變更作用域,因為函數的執行環境會隨著函數調用對象自動變更(指針this會指向超類).
最后,調用字面量對象的方法,方法執行中可能會使用this._super(),方法執行后,將屬性_super重置回其原來狀態,之后return退出函數。
以上可以有許多種方案能達到相同的效果(我之前曾見過將super綁定到其自身,然后用arguments.callee訪問),但是感覺還是這種方法最能能體現可用性與簡潔性的特點。
在我已完成的多個基于javascript原型的工作中,只有這個類繼承實現方案是我發表出來與大家分享的。我認為,簡潔的代碼(易于學習,易于繼承,更少下載)更需要提出來讓大家探討,因此,對于學習javascript類構造與繼承的人們來說,這套實現方案是一個好的開始。
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com