單例模式: 目的是創(chuàng)建全局唯一可用的對(duì)象
var createMask = function(){
return document.body.appendChild( document.createElement(div));
}
$( 'button' ).click( function(){
var mask = createMask();
mask.show();
})
// 缺點(diǎn): 那么每次調(diào)用createMask都會(huì)創(chuàng)建一個(gè)新的div,
var mask;
var createMask = function(){
if ( mask ) {
return mask;
}else{
mask = document,body.appendChild( document.createElement(div) );
return mask;
}
}
//這里函數(shù)內(nèi)改變了外界變量mask,而且mask是全局變量并不是非需不可;
var getSingle = (function(){
var single;
return function(fn){
return single || (single = fn.apply(this, arguments));
}
})()
// 使用
// 無(wú)論執(zhí)行多少次createSingleDiv(), 都只返回同一個(gè)div
var createSingleDiv = getSingle(function(){
return document.createElement('div')
})
/**
* 這種方法本質(zhì)上是緩存函數(shù)結(jié)果,并且限制函數(shù)只執(zhí)行一次。
* 這里使用單例主要是針對(duì)那些全局只有一個(gè)就可以的對(duì)象,多于1個(gè)就浪費(fèi)。
*/
訂閱-發(fā)布者模式 (觀察者模式)
觀察者模式又叫發(fā)布訂閱模式(Publish/Subscribe),它定義了一種一對(duì)多的關(guān)系,讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象的狀態(tài)發(fā)生變化時(shí)就會(huì)通知所有的觀察者對(duì)象,使得它們能夠自動(dòng)更新自己。
使用觀察者模式的好處:
- 支持簡(jiǎn)單的廣播通信,自動(dòng)通知所有已經(jīng)訂閱過(guò)的對(duì)象。
- 頁(yè)面載入后目標(biāo)對(duì)象很容易與觀察者存在一種動(dòng)態(tài)關(guān)聯(lián),增加了靈活性。
- 目標(biāo)對(duì)象與觀察者之間的抽象耦合關(guān)系能夠單獨(dú)擴(kuò)展以及重用。
publish/subscribe 模式使用了一個(gè)主題/事件通道,這個(gè)通道介于希望接收到通知(訂閱者)和激活事件的對(duì)象(發(fā)布者)之間。目的是避免訂閱者和發(fā)布者之間產(chǎn)生依賴(lài)關(guān)系
/**
* publish/subscribe 實(shí)現(xiàn)
* topics = [
* { topic1: [ {token: '', func: func}, {token: '', func: func}, ...]},
* { topic2: [ {token: '', func: func}, {token: '', func: func}, ...]},
* ]
*/
var pubsub = {};
(function(q){
var topics = {},
subUid = -1;
//發(fā)布或廣播事件,包含特定的topics名稱(chēng)和參數(shù)
q.publish = function(topic,args){
if(!topics[topic]){
return false;
}
var subscribers = topics[topic],
len = subscribers ? subscribers.length : 0;
while(len--){
subscribers[len].func(topic,args);
}
return this;
};
//通過(guò)特定的名稱(chēng)和回調(diào)函數(shù)訂閱事件,topic/event觸發(fā)時(shí)執(zhí)行事件
q.subscribe = function( topic, func){
if(!topics[topic]){
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
})
return token;
};
//基于訂閱上的標(biāo)記引用,通過(guò)特定topic取消訂閱
q.unsubscribe = function(token) {
for(var m in topics){
if(topics[m]){
for(var i = 0, j = topics[m].legnth; i < j; i++){
if(topics[m][i].token == token){
topics[m].splice(i, 1);
return token;
}
}
}
}
return this;
};
}(punsub))
/**
* * 使用上述實(shí)現(xiàn)示例. 消息處理程序
*/
var messageLogger = function( topics, data){
console.log('Logging: ' + topics + ":" + data);
}
//訂閱者監(jiān)聽(tīng)訂閱的topic,一旦該topic廣播一個(gè)通知,訂閱者就調(diào)用回調(diào)函數(shù)
var subscription = pubsub.subscribe('inbox/newMessage', messageLogger);
//發(fā)布者負(fù)責(zé)發(fā)布程序感興趣的topic或通知
pubsub.publish('inbox/newMessage', 'hello world');
// or
pubsub.publish('inbox/newMessage', ['test','a','b','c']);
//or
pubsub.publish('inbox/newMessage', { sender: 'hello@google.com', body: 'hey again!'})