var Event = (function() {
var global = this,
Event,
_default = 'default'; Event = function() {
var _create,
_listen,
_trigger,
_remove,
_shift = Array.prototype.shift,
_unshift = Array.prototype.unshift,
namespaceCache = {},
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);
}; _trigger = function() {
var cache = _shift.call(arguments),
key = _shift.call(arguments),
args = arguments,
_self = this,
stack = cache[key]; if (!stack || !stack.length) return; return each(stack, function() {
return this.apply(_self, args);
});
}; _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] = [];
};
};
}; _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;
}, 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();
}, remove: function(key, fn) {
_remove(key, cache, fn);
}, one: function(key, fn, last) {
_remove(key, cache);
this.listen(key, fn, last);
} };
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('evt1', 1, 2);
event.trigger('evt1', 3, 4); // 都存到offlineStack中去了 event.listen('evt1', e1); // 当有listen监听时,遍历offlineStack中的方法,发给第一次的listen
event.listen('evt1', e2);*/ /*// 先订阅后发布
event.listen('evt1', e1);
event.listen('evt1', e2); // 先订阅的事件都存到cache对象中去了 event.trigger('evt1', 1, 2); // 每次发布,都会遍历cache对象中对象事件名的数组
event.trigger('evt1', 3, 4); */ /*// 先发布后订阅 listen方法第三个参数可以是last,只有只会去多个trigger中的最后一个
event.trigger('evt1', 1, 2); // 1).
event.trigger('evt1', 3, 4); // 2). 都存到offlineStack中去了 event.listen('evt1', e1, 'last'); // 只会收到2).这个trigger*/ /*// 先订阅后发布再删除然后再发布,会发现evt1事件对象的cache[key]数组中少了e1函数,所以
// 再次发布只有e2执行了
event.listen('evt1', e1);
event.listen('evt1', e2); event.trigger('evt1', 1, 2);
event.remove('evt1', e1);
event.trigger('evt1', 3, 4);*/ // 订阅的再多,也只使用一个订阅
/*// 1). 先订阅后发布
event.one('evt1', e1);
event.one('evt1', e2); // 会使用这个,因为前一个被删了 event.trigger('evt1', 11, 22); // 所以会执行两次e2函数
event.trigger('evt1', 33, 44);*/ // 2). 先发布后订阅
/*event.trigger('evt1', 11, 22); // 所以会执行两次e2函数
event.trigger('evt1', 33, 44); event.one('evt1', e1); // 会使用这个,因为offlineStack被置为null了
event.one('evt1', e2); // 这个不执行了,需要等到下次trigger才会触发,因为e1从cache中删掉了,加入了e2, 如果后面还有one方法以此类推,会删除上一个监听的函数,添加新的监听函数*/ // 3). 先发布后订阅 one方法的第三个参数last会只接收最后一个trigger
event.trigger('evt1', 11, 22);
event.trigger('evt1', 33, 44); event.one('evt1', e2, 'last');
event.one('evt1', e1, 'last');

JavaScript设计模式 - 订阅发布模式(观察者模式)的更多相关文章

  1. 设计模式---订阅发布模式(Subscribe/Publish)

    设计模式---订阅发布模式(Subscribe/Publish) 订阅发布模式定义了一种一对多的依赖关系,让多个订阅者对象同时监听某一个主题对象.这个主题对象在自身状态变化时,会通知所有订阅者对象,使 ...

  2. [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  3. 学习javascript设计模式之发布-订阅(观察者)模式

    1.发布-订阅模式又叫观察者模式,它定义对象之间一种一对多的依赖关系. 2.如何实现发布-订阅模式 2-1.首先指定好发布者 2-2.给发布者添加一个缓冲列表,用户存放回调函数以便通知订阅者 2-3. ...

  4. js设计模式之代理模式以及订阅发布模式

    为啥将两种模式放在一起呢?因为这样文章比较长啊. 写博客的目的我觉得首要目的是整理自己的知识点,进而优化个人所得知识体系.知识成为个人的知识,就在于能够用自己的话表达同一种意义. 本文是设计模式系列文 ...

  5. Java里观察者模式(订阅发布模式)

    创建主题(Subject)接口 创建订阅者(Observer)接口 实现主题 实现观察者 测试 总结 在公司开发项目,如果碰到一些在特定条件下触发某些逻辑操作的功能的实现基本上都是用的定时器 比如用户 ...

  6. AngularJS的简单订阅发布模式例子

    控制器之间的交互方式广播 broadcast, 发射 emit 事件 类似于 js中的事件 , 可以自己定义事件 向上传递直到 document 在AngularJs中 向上传递直到 rootScop ...

  7. Publisher/Subscriber 订阅-发布模式

    Publisher/Subscriber 订阅-发布模式 本博后续将陆续整理这些年做的一些预研demo,及一些前沿技术的研究,与大家共研技术,共同进步. 关于发布订阅有很多种实现方式,下面主要介绍WC ...

  8. JavaScript设计模式之----组合模式

    javascript设计模式之组合模式 介绍 组合模式是一种专门为创建Web上的动态用户界面而量身制定的模式.使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为.这可以简化粘合性代码,使其更 ...

  9. RabbitMQ下的生产消费者模式与订阅发布模式

    所谓模式,就是在某种场景下,一类问题及其解决方案的总结归纳.生产消费者模式与订阅发布模式是使用消息中间件时常用的两种模式,用于功能解耦和分布式系统间的消息通信,以下面两种场景为例: 数据接入   假设 ...

随机推荐

  1. HappenBefore

    计算机芯片在操作指令的步骤: 1.获取指令 2.指令进行解码 3.去寄存器里取值 4.开始计算结果(操作) 5.将结果写会到寄存器中 执行代码的顺序可能与编写代码不一致,及虚拟机优化代码顺序,则为指令 ...

  2. Python 函数介绍

    函数的作用 1.减少重复代码 2.方便修改,更易扩展 3.保持代码一致性 函数的命名规则: 1.函数名必须以下划线或字母开头,可以包含任意字母,数字或下划线的组合,不能使用任何的标点符号. 2.函数名 ...

  3. 【读书笔记】iOS-解析XML

    使用最广泛的解析XML文档的方法有两种,一种基于SAX,另一种基于DOM.SAX解析器是事件驱动型的,在解析时增量地读取XML文档,当解析器识别出一个结点的时候会调用相应的委托方法. 参考资料< ...

  4. mysql从入门到放弃-入门知识介绍

    数据库在互联网网站的重要性 简单地说,数据库就是一个存放数据的仓库,这个仓库是按照一定的数据结构来组织和存储的,我们可以通过数据库提供的多种方法来管理数据库里的数据.由于数据库不易扩展,所以,在一个互 ...

  5. 排错-Loadrunner添加Windows Resource计数器提示“找不到网络路径”解决方法

    Loadrunner添加Windows Resource计数器提示“找不到网络路径”解决方法 by:授客 QQ:1033553122 1.启动windows相关服务 win->services. ...

  6. 安卓开发中strings.xml的使用

    为了使用方便也是为了代码规范化,我们都将文字信息放在res-values-strings.xml中, 因为开发中需要用到将文字的换行,百度了一下,可以将文字段信息直接在strings.xml文件中换行 ...

  7. MSSQL一种取代游标的方案

    今天看到一篇文章写的自己整理记录下,据说比用游标快. DECLARE @字段1 数据类型; DECLARE @字段2 数据类型; DECLARE @TMP_WHILE_ID INT; ,),TMP_W ...

  8. Java同步、异步区别

    一.概念: 1.同步:所有的操作都做完,才返回给用户.这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉).这种情况下,用户不 ...

  9. Chrome 如何让光标快速定位到地址栏-进行搜索

    我们经常花费大量的时间来进行使用浏览器搜索网页,如何进行高效的搜索,需要掌握一些快捷键: Windows: Ctrl + L 或 Alt + D 或 F6 Mac: Command + L Linux ...

  10. iOS时间显示今天昨天

    一.前言 今天无意间想起写这个功能,仔细考虑了一下,其实很简单,整体思路如下: 先获取你所要转换的时间的年月日,然后再获取今天和昨天的年月日,然后对比,进而返回不同的字符串. 二.实现步骤 首先,我们 ...