JavaScript設計模式,javascript模式
前言
最近看了一下《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這個新對象的過程:
模組(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方法很容易實現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):設計模式之享元模式
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。