一。原型模式
以現有的對象為原型,通過 clone 得到新的對象(以簡化新對象的創建過程)
(引自 [黯羽輕揚:設計模式總結(《Head First 設計模式》學習總結)](/articles/設計模式總結(《head-first 設計模式》學習總結)/))
和繼承很像,把原型模式繼續增強就是繼承了。原型模式只關心屬性複製,而繼承除了實現屬性複製外還要保證父/子類型的層級關係
二。具體實現
###1. 基本原理
// 生孩子函數
function beget(obj) {
var F = function() {};
F.prototype = obj;
return new F();
}
// test
var obj = {
attr: 1,
fun: function() {
console.log(this.attr);
}
}
var cp_obj = beget(obj);
cp_obj.fun(); // 1
核心就是 beget 函數,把傳入的對象塞進空構造函數原型裡,創建對象並返回,僅此而已
有一個明顯的缺點:來自原型對象(在此例中是 obj)的屬性可能會被不小心覆蓋掉
P.S. 原型對象 obj 可以是以任何方式創建的對象,在此例中是對象字面量,當然也可以是 new 出來的,可以是 beget 出來的等等
###2. 簡單增強
ES5 支持 Object.create 函數獲取淺拷貝的對象,可以直接把 beget 換成:
Object.create(obj);
結果完全一樣,因為 Object.create 內部實現就是受到道格拉斯原型模式的啟發,此外 Object.create 還可以有第二個參數,用來定義屬性:
Object.create(obj, {
attr: {
value: 2,
writable: false, // 預設值
configurable: false, // 預設值
enumerable: true
}
});
其實就是把 Object.create 和 Object.defineProperty 合在一起了,例如:
// test
var obj = {
attr: 1,
fun: function() {
console.log(this.attr);
}
}
var cp_obj = Object.create(obj, {
attr2: {
value: 2,
writable: false, // 預設值
configurable: false, // 預設值
enumerable: true
}
});
cp_obj.fun(); // 1
console.log(cp_obj.attr2); // 2
cp_obj.attr2 = 3;
console.log(cp_obj.attr2); // 2,不可寫
當然,Object.defineProperty 也是 ES5 才支持,所以配合使用算是一種增強(訪問控制)
三。原型模式的好處
書上有一句很不錯的話:
使用 Prototype 模式的其中一個好處是,我們獲得的是 JavaScript 其本身所具有的原型優勢,而不是試圖模仿其他語言的特性。
用 Java 實現的原型模式看起來很怪異,因為就原型模式本身而言,Java 中的 Object.clone 就可以滿足需要了,其它任何形式的實現都顯得多餘,而 JavaScript 最初沒有提供 clone 原生實現(ES5 的 Object.create 算是彌補了這個缺陷),所以需要原型模式,ES5 投入生產之後就不需要手動實現什麼原型模式了
更多關於原型模式的介紹請查看 23 種設計模式(5):原型模式
參考資料
-
《JavaScript 設計模式》
暫無評論,快來發表你的看法吧