面向對象的JavaScript --- 動態類型語言


面向對象的JavaScript --- 動態類型語言


動態類型語言與面向接口編程

JavaScript 沒有提供傳統面向對象語言中的類式繼承,而是通過原型委托的方式來實現對象與對象之間的繼承。
JavaScript 也沒有在語言層面提供對抽象類和接口的支持。

正因為存在這些跟傳統面向對象語言不一致的地方,我們在用設計模式編寫代碼的時候,更要跟傳統面向對象語言加以區別。我們有必要先了解一些 JavaScript 在面向對象方面的知識。

編程語言按照數據類型大體可以分為兩類,一類是靜態類型語言,另一類是動態類型語言。

靜態類型語言在編譯時便已確定變量的類型,而動態類型語言的變量類型要到程序運行的時候,待變量被賦予某個值之后,才會具有某種類型。

靜態類型語言的優點:
  1. 在編譯時就能發現類型不匹配的錯誤,編輯器可以幫助我們提前避免程序在運行期間有可能發生的一些錯誤。
  2. 如果在程序中明確地規定了數據類型,編譯器還可以針對這些信息對程序進行一些優化工作,提高程序執行速度。
靜態類型語言的缺點:
  1. 迫使程序員依照強契約來編寫程序,為每個變量規定數據類型,歸根結底只是輔助我們編寫可靠性高程序的一種手段,而不是編寫程序的目的,畢竟大部分人編寫程序的目的是為了完成需求交付生產。
  2. 類型的聲明也會增加更多的代碼,在程序編寫過程中,這些細節會讓程序員的精力從思考業務邏輯上分散開來。

動態類型語言的優點:
  編寫的代碼數量更少,看起來也更加簡潔,程序員可以把精力更多地放在業務邏輯上面。雖然不區分類型在某些情況下會讓程序變得難以理解,但整體而言,代碼量越少,越專注於邏輯表達,對閱讀程序是越有幫助的。
動態類型語言的缺點:
  無法保證變量的類型,從而在程序的運行期有可能發生跟類型相關的錯誤。這好像在商店買了一包牛肉辣條,但是要真正吃到嘴里才知道是不是牛肉味。

在 JavaScript 中,當我們對一個變量賦值時,顯然不需要考慮它的類型,因此,JavaScript是一門典型的動態類型語言。動態類型語言對變量類型的寬容給實際編碼帶來了很大的靈活性。由於無需進行類型檢測,我們可以嘗試調用任何對象的任意方法,而無需去考慮它原本是否被設計為擁有該方法。

這一切都建立在鴨子類型(duck typing)的概念上,通俗說法是:“如果它走起路來像鴨子,叫起來也是鴨子,那么它就是鴨子。 ”

通過一個小故事來更深刻地了解該類型:

從前在 JavaScript 王國里,有一個國王,他覺得世界上最美妙的聲音就是鴨子的叫聲,於是國王召集大臣,要組建一個 1000 只鴨子組成的合唱團。大臣們找遍了全國,終於找到999只鴨子,但是始終還差一只,最后大臣發現有一只非常特別的雞,它的叫聲跟鴨子一模一樣,於是這只雞就成為了合唱團的最后一員。

這個故事告訴我們,國王要聽的只是鴨子的叫聲,這個聲音的主人到底是雞還是鴨並不重要。鴨子類型指導我們只關注對象的行為,而不關注對象本身。

用代碼來模擬這個故事:

var duck = {
    duckSinging: function(){
        console.log( '嘎嘎嘎' );
    }
};
var chicken = {
    duckSinging: function(){
        console.log( '嘎嘎嘎' );
    }
};
var choir = []; // 合唱團
var joinChoir = function( animal ){
    if ( animal && typeof animal.duckSinging === 'function' ){
        choir.push( animal );
        console.log( '恭喜加入合唱團' );
        console.log( '合唱團已有成員數量:' + choir.length );
    }
};
joinChoir( duck ); // 恭喜加入合唱團
joinChoir( chicken ); // 恭喜加入合唱團

我們看到,對於加入合唱團的動物,根本無需檢查它們的類型,而是只需要保證它們擁有duckSinging方法。如果下次期望加入合唱團的是一只小狗,而這只小狗剛好也會鴨子叫,這只小狗也能順利加入。

在動態類型語言的面向對象設計中,鴨子類型的概念至關重要。利用鴨子類型的思想,我們不必借助超類型的幫助,就能輕松地在動態類型語言中實現一個原則:“面向接口編程,而不是面向實現編程”。例如,一個對象若有 push 和 pop 方法,並且這些方法提供了正確的實現,它就可以被當作棧來使用。一個對象如果有length屬性,也可以依照下標來存取屬性(最好還要擁有 slice 和 splice 等方法),這個對象就可以被當作數組來使用。

在靜態類型語言中,要實現“面向接口編程”並不是一件容易的事情,往往要通過抽象類或者接口等將對象進行向上轉型。當對象的真正類型被隱藏在它的超類型身后,這些對象才能在類型檢查系統的“監視”之下互相被替換使用。只有當對象能夠被互相替換使用,才能體現出對象多態性的價值。

“面向接口編程”是設計模式中最重要的思想,但在JavaScript語言中,“面向接口編程”的過程跟主流的靜態類型語言不一樣,因此,在 JavaScript 中實現設計模式的過程與在一些我們熟悉的語言中實現的過程會大相徑庭。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM