本文是《javascript設計模式與開發實踐》一書學習筆記,因書中所表述的概念簡單明瞭,故將整本書的筆記奉上,所有文章大概在20篇左右,還請朋友們持續關注javascript
編程語言按照數據類型大致能夠分爲兩類,一類是靜態類型語言,另外一類是動態類型語言java
靜態類型語言,聲明任何變量或者形參都須要指定類型,例如java語言。
動態類型語言,聲明任何變量或者形參都不須要指定類型,javascript就是動態類型語言。編程
所謂動態,能夠多層面的理解,首先,聲明變量不須要指定類型,其次,在多態思想下,java中須要利用父類實現多態,而javascript就不須要,自己自帶多態屬性。設計模式
熟悉java的朋友知道,java三大特徵之一就有多態,多態給java帶來了很大的靈活性,不少設計模式也是經過多態來實現,java中的多態涉及到向上轉型和向下轉型,而javascript(如下簡稱js)的"多態"就相對來講容易實現安全
咱們來看一段「多態」的js代碼編程語言
var makeSound = function(an) { if(an instanceof Duck) { console.log("嘎嘎嘎"); } else if(an instanceof Dog) { console.log("汪汪汪"); } } var Dog = function(){}; var Duck = function(){}; makeSound(new Dog()); makeSound(new Duck());
這段代碼確實體現了「多態性」,當咱們分別向鴨和雞發出「叫喚」的消息時,它們根據此 消息做出了各自不一樣的反應,可是這樣寫會有一個弊端,當更多的類型出現時,咱們要不斷的修改makeSound函數,後期makeSound函數也會變得十分巨大,這不符合良好代碼設計的規範,多態背後的思想是將「作什麼」和「誰去作以及怎樣去作」分離開來,也就是將「不變的事 物」與 「可能改變的事物」分離開來。在這個故事中,動物都會叫,這是不變的,可是不一樣類 型的動物具體怎麼叫是可變的。把不變的部分隔離出來,把可變的部分封裝起來,這給予了咱們 擴展程序的能力,程序看起來是可生長的,也是符合開放—封閉原則的,相對於修改代碼來講, 僅僅增長代碼就能完成一樣的功能,這顯然優雅和安全得多函數
首先,咱們把makeSound函數修改一下:學習
var makeSound = function(an) { an.speak(); }
這段代碼傳入一個對象,而後調用對象的speak函數prototype
var Duck = function(){} Duck.prototype.sound = function(){ console.log( '嘎嘎嘎' ); }; var Chicken = function(){} Chicken.prototype.sound = function(){ console.log( '咯咯咯' ); }; makeSound( new Duck() ); // 嘎嘎嘎 makeSound( new Chicken() );
如今咱們向鴨和雞都發出「叫喚」的消息,它們接到消息後分別做出了不一樣的反應。若是有 一天動物世界裏又增長了一隻狗,這時候只要簡單地追加一些代碼就能夠了,而不用改動之前的 makeSound 函數設計
如今,咱們來進一步瞭解多態,以前說到,java的多態須要利用繼承來實現,咱們如今把動物的例子換成java代碼
public class Duck { public void speak(){ System.out.println( "嘎嘎嘎" ); } } public class Dog { public void speak(){ System.out.println( "汪汪汪" ); } } public class AnimalSpeak{ public void makeSound(Duck duck){ duck.speak(); } } public static void main(String args[]){ AnimalSpeak an = new AnimalSpeak(); Duck duck = new Duck(); an.makeSound(duck); // 輸出:嘎嘎嘎 }
如今鴨子已經順利叫出來了,可是咱們想讓狗也叫,發現不太容易實現,由於makeSound函數中,形參是Duck類型,傳入Dog類型必定會報錯,這個時候繼承就出現了,java設計思路是我先建立一個父類,具體傳入的類型由子類決定,可是makeSound函數中的形參確是父類類型,實現以下:
public abstract class Animal{ abstract void speak(); // 抽象方法 } public class Duck extends Animal { public void speak(){ // 覆寫父類中的抽象方法 System.out.println( "嘎嘎嘎" ); } } public class Dog extends Animal { public void speak(){ // 覆寫父類中的抽象方法 System.out.println( "汪汪汪" ); } } public class AnimalSpeak{ public void makeSound(Animal an){ an.speak(); } } public static void main(String args[]){ AnimalSpeak an = new AnimalSpeak(); Animal duck = new Duck(); Animal dog = new Dog(); an.makeSound(duck); // 輸出:嘎嘎嘎 an.makeSound(dog); // 輸出:汪汪汪 }
JavaScript 對象的多態性是與生俱來的,爲何這麼說? 仔細看看這兩個函數:
public void makeSound(Animal an){ an.speak(); } function(an) { an.speak(); }
js和java中的函數的形參是不一樣的,java定死了傳入的類型,而js是動態的,js隨即可以傳入任何類型,因此,咱們以前說js是動態類型語言,在 JavaScript 這種將函數做爲一等對象的語言中,函數自己也是對象,函數用來封裝行爲並 且可以被四處傳遞。當咱們對一些函數發出「調用」的消息時,這些函數會返回不一樣的執行結 果,這是「多態性」的一種體現,也是不少設計模式在 JavaScript 中能夠用高階函數來代替實現的緣由。