《JavaScript設計模式與開發實踐》上,講到js的多態,我覺得書上的例子還是挺好的,特此總結一下。
多態就是 同一個操作 作用於不同的對象上面,會產生不同的解釋和不同的執行結果。或者說,給不同的對象發送同一個消息的時候,這些對象會根據這個消息分別給出不同的反饋。
主人家裏養了兩隻動物,分別是一隻鴨和一隻雞,當主人向它們出“叫”的命令時,鴨會“嘎嘎嘎”地叫,而雞會“咯咯咯”地叫。這兩隻動物都會以自己的方式來發出叫聲。它們同樣“都是動物,並且可以發出叫聲”,但根據主人的指令,它們會各自發出不同的叫聲。
//有多態思想,但是擴展性差,多來一隻狗,還要改動makeSound函數,易出錯
var makeSound = function( animal ){
if ( animal instanceof Duck ){
console.log( '嘎嘎嘎' );
}else if ( animal instanceof Chicken ){
console.log( '咯咯咯' );
}
};
var Duck = function(){};
var Chicken = function(){};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯
多態的基本思想就是:將“做什麼” 和與“誰去做、怎麼去做”分離開來;或者說把不變的事物 與 可能改變的事物 分離開來。
在這個故事中,動物都會叫,這是不變的,但是不同類型的動物具體怎麼叫是可變的。把不變的部分隔離出來,把可變的部分封裝起來,這給予了我們擴展程序的能力,程序看起來是可生長的,也是符合開放—封閉原則的,相對於修改代碼來說,僅僅增加代碼就能完成同樣的功能,這顯然優雅和安全得多。
var maskSound = function(animal){
animal.sound();
}
var Chicken = function(){}
Chicken.prototype.sound=function(){
console.log('咯咯咯');
}
var Duck = function(){}
Duck.prototype.sound = function(){
console.log( '嘎嘎嘎' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯
擴展:來了一隻狗,會叫的函數不用變,只需添加上狗怎麼叫的代碼就行。
var Dog = function(){}
Dog.prototype.sound = function(){
console.log( '汪汪汪' );
};
makeSound( new Dog() ); // 汪汪汪
JavaScript 對象的多態性是與生俱來的
JavaScript 的變量類型在運行期是可變的。一個 JavaScript 對象,既可以表示 Duck 類型的 對象,又可以表示Chicken 類型的對象,這意味着 JavaScript 對象的多態性是與生俱來的。 這種與生俱來的多態性並不難解釋。
JavaScript 作爲一門動態類型語言,它在編譯時沒有類型 檢查的過程,既沒有檢查創建的對象類型,又沒有檢查傳遞的參數類型。
在上面代碼示例中, 我們既可以往 makeSound 函數裏傳遞 duck 對象當作參數,也可以傳遞 chicken 對象當作參數。 由此可見,某一種動物能否發出叫聲,只取決於它有沒有 makeSound 方法,而不取決於它是否是某種類型的對象,這裏不存在任何程度上的“類型耦合”。這正是我們從上一節的鴨子類型 中領悟的道理。在 JavaScript 中,並不需要諸如向上轉型之類的技術來取得多態的效果。