JavaScript设计模式(发布订阅模式)
一、简单的发布-订阅模式
var salesOffices = {}; // 定义售楼处
salesOffices.clientList = []; // 缓存列表,存放订阅者的回调函数
salesOffices.listen = function( fn ){ // 增加订阅者
this.clientList.push( fn ); // 订阅的消息添加进缓存列表
};
salesOffices.trigger = function(){ // 发布消息
for( var i = 0, fn; fn = this.clientList[ i++ ];) {
fn.apply( this, arguments ); // arguments 是发布消息时带上的参数
}
};
salesOffices.listen( function( price, squareMeter ) { // 小明订阅者
console.log( '价格= ' + price );
console.log( 'squareMeter= ' + squareMeter );
});
salesOffices.listen( function( price, squareMeter ) { // 小红订阅者
console.log( '价格= ' + price );
console.log( 'squareMeter= ' + squareMeter );
});
salesOffices.trigger( 2000000, 88 ); // 输出: 价格= 2000000,squareMeter= 88 价格= 2000000,squareMeter= 88
salesOffices.trigger( 3000000, 110 ); // 输出: 价格= 3000000,squareMeter= 110 价格= 3000000,squareMeter= 110
var salesOffices = {}; // 定义售楼处
salesOffices.clientList = {}; // 缓存列表,存放订阅者的回调函数
salesOffices.listen = function( key, fn ){ // 增加订阅者
if(!this.clientList[key]) {
this.clientList[key] = []
}
this.clientList[key].push( fn ); // 订阅的消息添加进缓存列表
};
salesOffices.trigger = function(){ // 发布消息
var key = Array.prototype.shift.call( arguments ), // 取出消息类型
fns = this.clientList[ key ]; // 取出该消息对应的回调函数集合
if ( !fns || fns.length === 0 ){ // 如果没有订阅该消息,则返回
return false;
}
for( var i = 0, fn; fn = fns[ i++ ];) {
fn.apply( this, arguments ); // arguments 是发布消息时带上的参数
}
};
salesOffices.listen( 'squareMeter88', function( price ) { // 小明订阅者
console.log( '价格= ' + price );
});
salesOffices.listen( 'squareMeter110', function( price ) { // 小红订阅者
console.log( '价格= ' + price );
});
salesOffices.trigger( 'squareMeter88', 2000000); // 输出: 价格= 2000000
salesOffices.trigger( 'squareMeter110', 3000000); // 输出: 价格= 3000000
二、发布-订阅模式的通用实现
var event = {
clientList: [],
listen: function( key, fn ){
if ( !this.clientList[ key ] ){
this.clientList[ key ] = [];
}
this.clientList[key].push( fn ); // 订阅的消息添加进缓存列表
},
trigger: function() {
var key = Array.prototype.shift.call( arguments ), // (1);
fns = this.clientList[ key ];
if ( !fns || fns.length === 0 ){ // 如果没有绑定对应的消息
return false;
}
for( var i = 0, fn; fn = fns[ i++ ]; ){
fn.apply( this, arguments ); // (2) // arguments 是 trigger 时带上的参数
}
}
}
var installEvent = function( obj ){
for ( var i in event ){
obj[ i ] = event[ i ];
}
};
var salesOffices = {};
installEvent( salesOffices );
salesOffices.listen( 'squareMeter88', function( price ){
console.log( '价格= ' + price ); // 小明订阅消息
});
salesOffices.listen( 'squareMeter100', function( price ){
console.log( '价格= ' + price ); // 小红订阅消息
});
salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000
salesOffices.trigger( 'squareMeter100', 3000000 ); // 输出:3000000
event.remove = function( key, fn ){
var fns = this.clientList[ key ];
if ( !fns ){ // 如果 key 对应的消息没有被人订阅,则直接返回
return false;
}
if ( !fn ){ // 如果没有传入具体的回调函数,表示需要取消 key 对应消息的所有订阅
fns && ( fns.length = 0 );
}else{
for ( var l = fns.length - 1; l >=0; l-- ){ // 反向遍历订阅的回调函数列表
var _fn = fns[ l ];
if ( _fn === fn ){
fns.splice( l, 1 ); // 删除订阅者的回调函数
}
}
}
};
var salesOffices = {};
var installEvent = function( obj ){
for ( var i in event ){
obj[ i ] = event[ i ];
}
}
installEvent( salesOffices );
salesOffices.listen( 'squareMeter88', fn1 = function( price ){ // 小明订阅消息
console.log( '价格= ' + price );
});
salesOffices.listen( 'squareMeter88', fn2 = function( price ){ // 小红订阅消息
console.log( '价格= ' + price );
});
salesOffices.remove( 'squareMeter88', fn1 ); // 删除小明的订阅
salesOffices.trigger( 'squareMeter88', 2000000 ); // 输出:2000000
三、全局的发布-订阅对象
var Event = (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( var i = 0, fn; fn = fns[ i++ ]; ){
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 = fns.length - 1; l >=0; l-- ){
var _fn = fns[ l ];
if(_fn === fn){
fns.splice( l, 1 );
}
}
}
};
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
Event.listen( 'squareMeter88', function( price ){ // 小红订阅消息
console.log( '价格= ' + price ); // 输出:'价格=2000000'
});
Event.trigger( 'squareMeter88', 2000000 ); // 售楼处发布消息
四、总结
JavaScript设计模式(发布订阅模式)的更多相关文章
- javascript设计模式——发布订阅模式
前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...
- javascript 设计模式 -- 发布/订阅模式
直接上代码: index.html : <!DOCTYPE html> <html lang="en"> <head> <meta cha ...
- 设计模式-发布订阅模式(javaScript)
1. 前言 2. 什么是发布订阅模式 3. 发布订阅优缺点 4. 举例 4. 总结 1. 前言 发布订阅者模式是为了发布者和订阅者之间避免产生依赖关系,发布订阅者之间的订阅关系由一个中介列表来维护.发 ...
- js设计模式--发布订阅模式
前言 本系列文章主要根据<JavaScript设计模式与开发实践>整理而来,其中会加入了一些自己的思考.希望对大家有所帮助. 概念 发布-订阅模式又叫观察者模式,它定义对象间的一种一对多的 ...
- [转]js设计模式—发布订阅模式
发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模式.本文将 ...
- [转] 浅析JavaScript设计模式——发布-订阅/观察者模式
前一段时间一直在写CSS3的文章 一直都没写设计模式 今天来写写大名鼎鼎观察者模式 先画张图 观察者模式的理解 我觉得还是发布-订阅模式的叫法更容易我们理解 (不过也有的书上认为它们是两种模式……) ...
- js设计模式-发布/订阅模式
一.前言 发布订阅模式,基于一个主题/事件通道,希望接收通知的对象(称为subscriber)通过自定义事件订阅主题,被激活事件的对象(称为publisher)通过发布主题事件的方式被通知. 就和用户 ...
- Javascript设计模式之发布-订阅模式
简介 发布-订阅模式又叫做观察者模式,他定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖他的对象都会得到通知. 回忆曾经 作为一名前端开发人员,给DOM节点绑定事件可是再频繁不过 ...
- 理解JavaScript设计模式与开发应用中发布-订阅模式的最终版代码
最近拜读了曾探所著的<JavaScript设计模式与开发应用>一书,在读到发布-订阅模式一章时,作者不仅给出了基本模式的通用版本的发布-订阅模式的代码,最后还做出了扩展,给该模式增加了离线 ...
- [转] JavaScript设计模式之发布-订阅模式(观察者模式)-Part1
<JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...
随机推荐
- LeetCode 215. 数组中的第K个最大元素(Kth Largest Element in an Array)
题目描述 在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 ...
- mysql中的utf8mb4、utf8mb4_unicode_ci、utf8mb4_general_ci的关系
mysql中的utf8mb4.utf8mb4_unicode_ci.utf8mb4_general_ci的关系 一.总结 一句话总结: utf8mb4是utf8的超集并完全兼容utf8,能够用四个字节 ...
- Devops(一):CentOS7 安装Maven3.6.1详解
https://yq.aliyun.com/topic/78?spm=5176.8290451.656547.7.rMYhAF https://yq.aliyun.com/activity/155?u ...
- C memcpy()用法
https://blog.csdn.net/qq_21792169/article/details/50561570
- win10下检查nvidia显卡支持的cuda版本
1.首先将[C:\Program Files\NVIDIA Corporation\NVSMI]添加至系统环境变量[path]中: 2.在powershell中使用命令[nvidia-smi],即可看 ...
- rally使用tempest进行测试
安装 通过Rally进行Tempest测试,执行如下命令创建tempest实例,Rally会自动同步tempest代码至本地: rally verify create-verifier --name ...
- 小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-4.微信授权一键登录开发之授权URL获取
笔记 4.微信授权一键登录开发之授权URL获取 简介:获取微信开放平台扫码连url地址 1.增加结果工具类,JsonData; 增加application.properties配置 ...
- idea中maven右键没有show dependencies选项
如图,idea高版本(2018.3.4)中maven 的右键没有show dependencies菜单 查看依赖包方法,双击pom.xml文件,在文件编辑页面右键maven或者diagrams弹出依赖 ...
- Cloudera Manager产品介绍
一.Cloudera Manager简介 Cloudera Manager(后面简称CM)是CDH(Cloudera’s Distribution Including Apache Hadoop)市场 ...
- 图解Go协程调度原理,小白都能理解
阅读本文仅需五分钟,golang协程调度原理,小白也能看懂,超实用. 什么是协程 对于进程.线程,都是有内核进行调度,有CPU时间片的概念,进行抢占式调度.协程,又称微线程,纤程.英文名Corouti ...