更好理解的面向對象的Javascript 1 —— 動態類型和多態

前言

曾經對Javascript的面向對象相關知識也有過了解,從各類博客、書籍上也學到了不少。可是最近在看《Javascript設計模式與開發實戰》這本書時發現該書對這方面的知識點介紹的很易於理解,所以總結出該文章分享給你們,同時也做爲本身往後複習的筆記。編程

動態類型語言和鴨子類型

編程語言按照數據類型大致可分爲靜態類型語言和動態類型語言。
靜態類型語言就是指在編譯時就已經肯定了變量的類型,好比C++在聲明變量時的int關鍵字。
動態類型語言的變量類型要在程序運行時被賦值後才能肯定。
在Javascript中,咱們在對一個變量賦值時,顯然不須要考慮它的類型。所以,Javascript是一門經典的動態類型語言。設計模式

動態類型語言在實際編碼時帶來了很大的靈活性,咱們能夠嘗試調用任意對象的任意方法,而不須要考慮它本來是否被設計擁有該方法。
這些都創建在鴨子類型的概念上,通俗的說法是「若是它走起路來像鴨子,叫起來也是鴨子,那麼它就是鴨子。」
好吧我知道你可能不太理解,咱們能夠經過一個故事來深刻理解:數組

從前在Javascript王國裏,有一個國王,他以爲世界上最美妙的聲音就是鴨子的叫聲,因而國王召集大臣,要組建一個100只鴨子組成的合唱團。可是大臣們找遍了全國,只找到了999只鴨子,最後大臣發現有一隻很是特別的雞,它的叫聲跟鴨子如出一轍,因而這隻雞就成爲了合唱團的最後一員。

這個故事說明,國王只是想要鴨子的叫聲,但它的主人是雞仍是鴨都不重要。咱們只關注對象的行爲,而不關注對象自己
經過代碼你可能能更好的的理解:編程語言

let duck = {
  duckSay: function () {
    console.log('ga')
  }
}

let chicken = {
  duckSay: function () {
    console.log('ga')
  }
}

// 合唱團
let choir = []

let joinChoir = function (animal) {
  if (animal && typeof animal.duckSay === 'function') {
    choir.push(animal)
    console.log('加入合唱團成功')
  }
}

joinChoir(duck)  // 加入合唱團成功
joinChoir(chicken)  // 加入合唱團成功

咱們發現,只要動物擁有duckSay方法,它就能夠加入合唱團,而並不關心它究竟是誰。
鴨子類型的概念相當重要,好比一個對象有了length屬性,也能夠依照下標來存取屬性,這個對象就能夠被當作數組來使用。(這裏能夠思考咱們在處理函數傳入的參數arguments時的一些操做)函數

多態

多態是指同一操做做用於不一樣的對象上面,能夠產生不一樣的解釋和不一樣的執行結果。也就是給不一樣對象發送同一消息,會有不一樣的反饋。
這裏咱們依舊經過一個故事來說解:google

主人家裏養了兩隻動物,一隻雞和一隻鴨,當主人發出叫的命令時,鴨會gagaga的叫,而雞會gegege的叫。

上面的故事用代碼實現就是:編碼

let makeSound = function (animal) {
  if (animal instanceof Duck) {
    console.log('ga')
  } else if (animal instanceof Chicken) {
    console.log('ge')
  }
}

let Duck = function () {}
let Chicken = function () {}

makeSound(new Duck())  // ga
makeSound(new Chicken())  // ge

多態背後的思想是將「作什麼」和「誰去作以及怎樣去作」分離開,即將「不變的事情」和「可變的事情」分離開。這樣的程序是可生長的,也是符合開放-封閉原則。
所以咱們能夠將不變的部分隔離出來,也就是全部的動物都會叫prototype

let makeSound = function (animal) {
  animal.sound()
}

而後把可變的部分封裝起來:設計

let Duck = function () {}
Duck.prototype.sound = function () {
  console.log('ga')
}

let Chicken = function () {}
Chicken.prototype.sound = function () {
  console.log('ge')
}

makeSound(new Duck())  // ga
makeSound(new Chicken())  // ge

再好比咱們要開發一個地圖應用,如今有百度和谷歌兩家地圖提供了API,且均提供了show()方法,代碼以下:code

let googleMap = {
  show: function () {
    console.log('開始渲染谷歌地圖')
  }
}

let baiduMap = {
  show: function () {
    console.log('開始渲染百度地圖')
  }
}

let renderMap = function (type) {
  if (type === 'google') {
    googleMap.show()
  } else if (type === 'baidu') {
    baiduMap.show()
  }
}

renderMap('google')  // 開始渲染谷歌地圖
renderMap('baidu')  // 開始渲染百度地圖

能夠看到,雖然renderMap()函數保持了必定的彈性,可是這種彈性很脆弱,若是再換另外一個地圖,有須要修改renderMap函數,繼續添加條件分支語句。
咱們能夠把程序相同的部分抽象出來,即顯示某個地圖:

let renderMap = function (map) {
  if (map.show instanceof Function) {
    map.show()
  }
}

結束語

但願能爲你帶來一些啓發。

參考資料: 《JavaScript 設計模式與開發實戰》 第一章
相關文章
相關標籤/搜索