《JavaScript設計模式與開發實踐》-面向對象的JavaScript
設計模式 面向對象
動態類型語言
編程語言按照數據類型大體分為:靜態類型語言和動態類型語言。
靜態類型語言在編譯時便已確定變量的類型,而動態類型語言的變量類型要到程序運行時,待變量被賦予某個值之後,才會具有某種類型。
在JavaScript中,當我們對一個變量賦值時,顯然不需要考慮它的類型,因此JavaScript是一門典型的動態類型語言。
動態類型語言對變量類型的寬容給實際編碼帶來了很大的靈活性,由於無需進行類型檢測,我們可以嘗試調用任何對象的任意方法,而無需去考慮它原本是否被設計為擁有該方法。
這一切都建立在鴨子類型的概念上,即如果它走起來像鴨子,叫起來也是鴨子,那麼它就是鴨子。
var duck = {
duckSinging: function() {
printf('gagaga');
}
};
var chicken = {
duckSinging: function() {
printf('gagaga');
}
};
var choir = [];
var joinChoir = function(animal) {
if (animal && typeof animal.duckSinging === "function") {
choir.push(animal);
printf("恭喜加入合唱團");
printf("合唱團已有人數" + choir.length);
}
}
joinChoir(duck);
joinChoir(chicken);
由此,實現了動態類型語言中的一個重要原則:面向接口編程,而不是面向實現編程。
多態
多態的實際含義是:同一操作作用域不同的對象上面,可以產生不同的解釋和不同的執行結果。
var makeSound = function(animal) {
if (animal instanceof Duck) {
printf('ggaga');
} else if (animal instanceof chicken) {
printf('gegege');
}
}
var Duck = function() {};
var chicken = function() {};
makeSound(new Duck());
makeSound(new chicken());
這段代碼確實實現了多態性,但是如何增加一只動物,那麼makeSound函數也需要去改動,這顯然並不讓人滿意。
多態背後的思想是將“做什麼”和“誰去做及怎樣做”分離開來,也就是將“不變的事物”與“可能改變的事物”分離開來。
原型編程范型的一些規則
所有的數據都是對象
要得到一個對象,不是通過實例化類,而是找到一個對象作為原型並克隆它
對象會記住它的原型
如果對象無法響應某個請求,它會把這個請求委托給它自己的原型
事實上,JavaScript中的根對象是Object.prototype,它是一個空對象,我們在JavaScript中遇到的每個對象,實際上都是從它克隆而來的。Object.prototype就是它們的原型。
雖然我們經常用new去實例化一個函數,但是在JavaScript中,當使用new運算符來調用函數時,實際上也是先克隆Object.prototype對象,再進行一些其他額外的過程。
我們一直在討論對象的原型,就JavaScript的真正實現來說,並不能說對象有原型,而應該說對象的構造器有原型。
實際上,雖然JavaScript的對象最初都是又Object.prototype對象克隆而來,但對象構造器的原型並不限於Object.prototype上,而是可以動態指向其他對象。這樣一來,當對象a需要借用對象b的能力時,可以有選擇性地把對象a的構造器的原型指向對象b,從而達到繼承的效果。
var A=function(){};
A.prototype={name:'sven'};
var B=function(){};
B.prototype.new A();
var b=new B();
console.log(b.name);//輸出:sven