標籤:iter [] pen art names 溝通 foo 方式 get
前言
近期看了一下《JavaScript設計模式》這本書。書中有非常多知識點,一時之間消化不了。先記下來。
ps:另有部分內容參考Tom大叔部落格深入理解JavaScript系列
構造器(Constructor)模式
Object構造器用於建立特定類型的對象——準備好對象以備使用,同一時候可接受構造器能夠使用的參數,以在第一次建立對象時,設定成員屬性和方法的值。
function Car(model, year, miles) { this.model = model; this.year = year; this.miles = miles; this.toString = function() { return this.model + " has done "+ this.miles + "miles"; };}
上面這就是一個簡單的構造器模式版本號碼。但有一個效能方面的問題:toString()這樣的方法是為每一個Car建立的新對象而分別又一次定義的。假設同一時候建立多個對象情況下。資源浪費比較嚴重。所以我們一般使用以下的帶原型(prototype)的構造器模式。
ps:一般推薦建構函式名以大寫字母開頭,以便區分普通函數。
function Car(model, year, mille) { this.model = model; this.year = year; this.mile = mile;}// 注意這裡使用Object.prototype.newMethod為了避免又一次定義prototype對象Car.prototype.toString = function() { return this.model + " has done " + this.miles + " miles";};var landRover = new Car("Land Rover", 2015, 10000);
如今toString的單一執行個體就能夠在全部Car對象之間共用。
上述在執行個體化landRover這個新對象的過程:
- 建立一個新對象,並讓this指標指向這個新對象
- 將建構函式的prototype對象成員賦值給新建立對象的原型鏈上
- 運行建構函式體內的代碼,初始化這個新對象
- 返回建立的新對象
模組(Module)模式
在js中,Module模式用於進一步類比類的概念。通過這樣的方式。能夠使一個單獨的對象擁有公有/私人方法和變數,從而屏蔽來自全域範圍的特殊部分。
(利用自運行函數和閉包概念)
var myNamespace = (function() { //私人計數器變數 var myPrivateVar = 0; // 私人函數 var myPrivateMethod = function(foo) { console.log(foo); }; return { //公有變數 myPublicVar: "foo", mYPublicFunction: function(bar) { myPrivateVar ++; myPrivateMethod(bar); } };})();
單例(Singleton)模式
“單例”顧名思義就是它限制了類的執行個體化次數僅僅能一次。而最簡單的單例模式就是對象字面量方式。
var mySingleton = { property: "myBlog", method: function() {}};
而上述類的靜態執行個體(對象)和Singleton之間差別:當Singleton能夠作為一個靜態執行個體實現時,它也能夠延遲構建,直到須要使用靜態執行個體時,能夠節約資源或記憶體。
//方式1var mySingleton1 = (function() { //執行個體保持了Singleton的一個應用 var instance; function init() { var privateVariable = "I‘m private"; function privateMethod() { console.log("I‘m private"); } return { publicProperty: "public", publicMethod: privateMethod }; } return { getInstance: function() { if (!instance) { instance = init(); } return instance; } };})();//方式2var mySingleton2 = function() { //緩衝執行個體 var instance = this; //其他內容 this.property = "value"; //重寫建構函式 mySingleton2 = function() { return instance; };};
觀察者(Observer)模式
觀察者模式又被稱為公布/訂閱(publish/subscribe)者模式。其中,一個對象(subject)維持一系列依賴於它的對象(觀察者),將有關狀態的不論什麼變更自己主動通知給他們。
使用觀察者模式能夠將應用程式分解為更小、更鬆散耦合的塊,以促進代碼管理和潛在複用。ps:該模式最直接的應用就是DOM事件綁定。
var pubSub = {};(function(q) { var topics = {}, subUid = -1; // 公布或廣播事件。包括特定的topic名稱和參數(比方傳遞的資料) q.publish = function(topic, args) { if (!topics[topic]) { return false; } var subscribers = topics[toppic], len = subscribers ? subscribers.length : 0; while (len--) { subscribers[len].func(topic, args); } return this; }; // 通過特定的名稱和回呼函數訂閱事件,topic/event觸發時運行事件 q.subscribe = function(topic, func) { if (!topics[topic]) { topics[topic] = []; } var token = (++subUid).toString; topics[topic].push({ token: token, func: func }); return token; }; // 基於訂閱上的標記引用。通過特定topic取消訂閱 q.unsubscribe = function(token) { for (var m in topics) { if (topics[m]) { for (var i = 0, j = topics[m].length; i < j; i++) { if (topics[m][i].token === token) { topics[m].splice(i, 1); return token; } } } } return false; };})(pubSub);
另外,能夠通過jQuery事件綁定on/off方法非常easy實現Publish/Subscribe模式:
(function ($) { var o = $({}); $.subscribe = function () { o.on.apply(o, arguments); }; $.unsubscribe = function () { o.off.apply(o, arguments); }; $.publish = function () { o.trigger.apply(o, arguments); };} (jQuery));
中介者(Mediator)模式
假設一個系統的各個組件之間看起來有太多的直接關係,或許是時候須要一個中心控制點,以便各個組件能夠通過這個中心控制點進行通訊。而中介者模式促進鬆散 耦合的方式是:確保組件的互動是通過這個中心點來處理的,而不是通過顯示地應用彼此。這樣的模式能夠協助我們解耦系統並提高組件的可重用性。現實世界中典型的一個範例就是機場的交通控制系統,機場控制塔就是充當這個中間點身份。
還有一個範例是DOM事件冒泡和事件託付。
假設系統中全部的訂閱針對的是文檔document而不是單個node節點,則這個文檔會有效地充其中介者。更進階別的對象承擔了向訂閱者通知有關互動事件的責任,而不是綁定到單個節點的事件。
var mediator = (function() { var topics = {}, subscribe = function(topic, fn) { if (!topics[topic]) { topics[topic] = []; } topics[topic].push({ context: this, callback: fn }); return this; }, publish = function(topic) { var args; if (!topics[topic]) { return false; } args = [].prototype.slice.call(arguments, 1); for (var i = 0, l = topics[topic].length; i < l; i++) { var subscription = topics[topic][i]; subscription.callback.apply(subscription.context, args); } return this; }; return { Publish: publish, Subscribe: subscribe, installTo: function(obj) { obj.subscribe = subscribe; obj.publish = publish; } };})();
中介者與觀察者
觀察者模式中。不存在封裝約束的單一對象。觀察者Observer和詳細類Subject是一起配合來維護約束的,溝通是通過多個觀察者和多個詳細類來互動的:每一個詳細類通常包括多個觀察者,而有時候詳細類裡的一個觀察者也是還有一個觀察者的詳細類。
而中介者模式通過限制對象嚴格通過Mediator進行通訊來實現這一目的。
原型(Prototype)模式
原型模式是一種基於現有對象模板。通過複製方式建立對象的模式。常見模式例如以下:不包括不論什麼初始化的概念,僅是將對象連結至原型。
var beget = (function() { function F() {}; return function(proto) { F.prototype = proto; return new F(); };})();
另外,ECMA5標準中定義了一個方法。Object.create(proto, [propertiesObject])建立一個擁有指定原型和若干個指定屬性的對象。該方法能夠輕易實現對象繼承,而不用通過一個空函數做過渡。
原廠模式
原廠模式不顯示地要求使用一個建構函式,通過提供一個通用的介面來建立對象,我們能夠指定所希望建立的工廠對象的類型。該模式使一個類的執行個體化延遲到了子類。而子類能夠重寫介面方法以便建立的時候指定自己的物件類型。
var Car = (function () { var Car = function (options) { this.doors = options.doors || 4; this.state = options.state || "brand new"; this.color = options.color || "silver"; }; return function (options) { return new Car(options); };})();
何時使用:
- 當對象或組件設定涉及高複雜性
- 當須要依據所在的不同環境輕鬆產生對象的不同執行個體時
- 當處理非常多共用同樣屬性的小型對象或組件時
裝飾著(Decorator)模式
裝飾著模式提供了將行為動態加入至系統的現有類的能力,並不嚴重依賴於建立對象的方式。而是關注擴充其額外功能。
基本想法是:向基本對象加入(裝飾)屬性或方法。而不是進行子類化。
裝飾者用於通過重載方法的形式加入新功能。該模式能夠在被裝飾者前面或者後面加上自己的行為以達到特定的目的,用於給不同的對象各自加入新行為。
// 被裝飾的物件建構函數function MacBook() { this.cost = function() {return 997;}; this.screenSize = function() {return 11.6};}// Decorator 1function Memory(macbook) { var v = macbook.cost(); macbook.cost = function() {return v + 75;};}// Decorator 2function Engraving(macbook) { var v = macbook.cost(); macbook.cost = function() {return v + 200;};}// Decorator 3function Insurance(macbook) { var v = macbook.cost(); macbook.cost = function() {return v + 250;};}
享元(Flyweight)模式
享元模式旨在通過與相關的對象共用儘可能多的資料來降低應用程式中記憶體的使用(如:應用程式配置。狀態等)。
享元模式的應用方式有兩種。第一種是用於資料層,處理記憶體中儲存的大量類似對象的共用資料。另外一種是用於DOM層。Flyweight能夠用作中央事件管理器,來避免將事件處理常式加入到父容器中的每一個子項目上,而是將事件處理常式附加到這個父容器上。
詳細能夠參考湯姆大叔的這篇博文——深入理解JavaScript系統(37):設計模式之享元模式
JavaScript設計模式