發佈—訂閱模式又叫觀察者模式,它定義對象間的一種一對多的依賴關係,當一個對象的狀 態發生改變時,全部依賴於它的對象都將獲得通知。在 JavaScript 開發中,咱們通常用事件模型 來替代傳統的發佈—訂閱模式。ajax
小明最近看上了一套房子,到了售樓處以後才被告知,該樓盤的房子早已售罄。好在售樓 MM 告訴小明,不久後還有一些尾盤推出,開發商正在辦理相關手續,手續辦好後即可以購買。 但究竟是何時,目前尚未人可以知道。 因而小明記下了售樓處的電話,之後天天都會打電話過去詢問是否是已經到了購買時間。除 了小明,還有小紅、小強、小龍也會天天向售樓處諮詢這個問題。一個星期事後,售樓 MM 決 定辭職,由於厭倦了天天回答 1000 個相同內容的電話。 固然現實中沒有這麼笨的銷售公司,實際上故事是這樣的:小明離開以前,把電話號碼留在 了售樓處。售樓 MM 答應他,新樓盤一推出就立刻發信息通知小明。小紅、小強和小龍也是一 樣,他們的電話號碼都被記在售樓處的花名冊上,新樓盤推出的時候,售樓 MM 會翻開花名冊,遍歷上面的電話號碼,依次發送一條短信來通知他們。設計模式
發送短信通知就是一個典型的發佈—訂閱模式,小明、小紅等購買者都是 訂閱者,他們訂閱了房子開售的消息。售樓處做爲發佈者,會在合適的時候遍歷花名冊上的電話號碼,依次給購房者發佈消息。bash
var DEvent = (function() {
var clientList = {},
listen,
trigger,
remove;
listen = function(key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
};
trigger = function() {
var key = Array.prototype.shift.call(arguments),
fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (let index = 0; index < fns.length; index++) {
const fn = fns[index];
fn.apply(this, arguments);
}
};
remove = function(key, fn) {
var fns = clientList[key];
if (!fns) {
return false;
}
if (!fn) {
fns && (fns.length = 0);
} else {
for (var l = fn.length - 1; l >= 0 ; l--) {
var _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1);
}
}
}
};
return {
listen,
trigger,
remove
};
})();
Event.listen( 'squareMeter88', function( price ){ // 小紅訂閱消息
console.log( '價格= ' + price ); // 輸出:'價格=2000000'
});
Event.trigger( 'squareMeter88', 2000000 );// 售樓處發佈消息
複製代碼
$.ajax( 'http:// xxx.com?login', function(data){ // 登陸成功
login.trigger('loginSucc', data); // 發佈登陸成功的消息
});
var header = (function(){ // header 模塊
login.listen( 'loginSucc', function( data){
header.setAvatar( data.avatar );
});
return {
setAvatar: function( data ){
console.log( '設置 header 模塊的頭像' );
}
}
})();
var nav = (function(){
login.listen( 'loginSucc', function( data ){// nav 模塊
nav.setAvatar( data.avatar );
});
return {
setAvatar: function( avatar ){
console.log( '設置 nav 模塊的頭像' );
}
}
})();
複製代碼
var Event = (function(){
var global = this,
Event,
_default = 'default';
Event = function(){
var _listen,
_trigger,
_remove,
_slice = Array.prototype.slice,
_shift = Array.prototype.shift,
_unshift = Array.prototype.unshift,
namespaceCache = {},
_create,
find,
each = function( ary, fn ){
var ret;
for ( var i = 0, l = ary.length; i < l; i++ ){
var n = ary[i];
ret = fn.call( n, i, n);
}
return ret;
};
_listen = function( key, fn, cache ){
if ( !cache[ key ] ){
cache[ key ] = [];
}
cache[key].push( fn );
};
_remove = function( key, cache, fn) {
if ( cache[ key ] ){
if( fn ){
for( var i = cache[ key ].length; i >= 0; i-- ){
if( cache[ key] [i] === fn) {
cache[key].splice(i, 1);
}
}
} else{
cache[ key ] = [];
}
}
};
_trigger = function(){
var cache = _shift.call(arguments),
key = _shift.call(arguments),
args = arguments,
_self = this,
ret,
stack = cache[ key ];
if ( !stack || !stack.length ) {
return;
}
return each( stack, function(){
return this.apply( _self, args );
});
};
_create = function( namespace ){
var namespace = namespace || _default;
var cache = {},
offlineStack = [],// 離線事件
ret = {
listen: function(key, fn, last ){
_listen(key, fn, cache );
if ( offlineStack === null ){
return;
}
if ( last === 'last' ){
offlineStack.length && offlineStack.pop()();
}else{
each( offlineStack, function(){
this();
});
}
offlineStack = null;
},
one: function( key, fn, last ){
_remove( key, cache );
this.listen( key, fn ,last );
},
remove: function( key, fn ){
_remove( key, cache ,fn);
},
trigger: function(){
var fn,
args,
_self = this;
_unshift.call( arguments, cache );
args = arguments;
fn = function(){
return _trigger.apply( _self, args );
};
if ( offlineStack ){
return offlineStack.push( fn );
}
return fn();
}
};
return namespace ?
( namespaceCache[ namespace ] ? namespaceCache[ namespace] :
namespaceCache[ namespace ] = ret ) : ret;
};
return {
create: _create,
one: function( key,fn, last ){
var event = this.create( );
event.one( key,fn,last );
},
remove: function( key,fn ){
var event = this.create( );
event.remove( key,fn );
},
listen: function( key, fn, last ){
var event = this.create( );
event.listen( key, fn, last );
},
trigger: function(){
var event = this.create( );
event.trigger.apply( this, arguments );
}
}; }();
return Event;
})();
複製代碼