一、什么是发布——订阅模式
发布订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知
二、发布——订阅模式的作用
1、用于异步编程,取代传递回调函数的方案
2、让两个对象松耦合地联系在一起,一个对象不再显式地调用另一个对象的接口
三、如何实现
1、三要素
发布者;
缓存列表;
订阅者的回调;
2、实现代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>监听者模式</title>
</head>
<body>
<script type="text/javascript">
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 (arr, fn) {
var ret;
for (var i = 0, l = arr.length; i < l; i++) {
var n = arr[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 =0,l=cache[key].length; i < l; i++) {
if (cache[key][i] === fn) {
cache[key].splice(i, 1);
i--;
}
}
} 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();
}
};
console.log(nameSpaceCache);
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;
})()
/**
* 先发布后订阅
*/
Event.trigger('click',1);
Event.listen('click',function(a){
console.log(a);
})
/**
* 使用命名空间
*/
Event.create('nameSpace1').listen('click',function(a){
console.log(a);
});
Event.create('nameSpace1').trigger('click',1);
Event.create('nameSpace2').listen('click',function(a){
console.log(a);
});
Event.create('nameSpace1').trigger('click',2);
</script>
</body>
</html>