跳到主要內容
黯羽輕揚每天積累一點點

原型模式_JavaScript 設計模式 6

免費2015-07-22#JS#Design_Pattern#JavaScript原型模式#Prototype_Pattern

原型模式,也就是道格拉斯的生孩子(beget)方法,以現有對象為原型,創建新對象,類似於繼承,但更像複製。本文詳細介紹 JavaScript 實現的原型模式

一。原型模式

以現有的對象為原型,通過 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.createObject.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):原型模式

參考資料

評論

暫無評論,快來發表你的看法吧

提交評論