学习JavaScript设计模式之观察者模式


Posted in Javascript onApril 22, 2020

一、定义

观察者模式(发布-订阅模式):其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
在JavaScript中,一般使用事件模型来替代传统的观察者模式。
好处:

  • (1)可广泛应用于异步编程中,是一种替代传递回调函数的方案。
  • (2)可取代对象之间硬编码的通知机制,一个对象不用再显示地调用另外一个对象的某个接口。两对象轻松解耦。

二、DOM事件?观察者模式典例

需要监控用户点击document.body的动作,但是我们没有办法预知用户将在什么时间点击。
所以,我们订阅document.body上的click事件,当body节点被点击时,body节点便向订阅者发布这个消息!

document.body.addEventListener("click", function() {
 console.log(1);
}, false);

// 可以多个订阅者
document.body.addEventListener("click", function() {
 console.log(2);
}, false);

doucment.body.click();

某网站有header头部、nav导航、消息列表等模块。这几个模块的渲染都需要获取用户登陆信息。

(1)一般写法:

$.ajax({
 url: './login',
 type: 'post',
 contentType: 'application/json',
 dataType:'json',
 success: function(data) {
 if(data.status === "success") {
  // 登录成功,渲染header、nav
  header.setInfo(data.headerInfo);
  nav.setInfo(data.navInfo);
 }
 }
});

(2)使用观察者模式,很轻松解耦!

$.ajax({
 ...,
 success: function(data) {
 if(data.status === "success") {
  // 登录成功,发布登陆成功消息
  login.trigger("loginsuccess", data);
 }
 }
});

var header = (function() {
 // 监听消息
 login.listen("loginsuccess", function(data){
 header.setInfo(data.headerInfo);
 });
 return {
 setInfo: function(data) {
  console.log("设置header信息");
 }
 };
})();

var nav = (function() {
 login.listen("loginsuccess", function(data){
 nav.setInfo(data.navInfo);
 });
 return {
 setInfo: function(data) {
  console.log("设置nav信息");
 }
 }
})();

三、通用观察者模式

/*
 * 示例:
 * Event.create("namespace1").listen('click', function(a){
 * console.log(a);
 * });
 * Event.create("namespace1").trigger("click", 1);
 */
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, last) {
   _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;
})();

希望本文所述对大家学习javascript程序设计有所帮助。

Javascript 相关文章推荐
jQuery 研究心得 取得属性的值
Nov 30 Javascript
js 单引号 传递方法
Jun 22 Javascript
javascript温习的一些笔记 基础常用知识小结
Jun 22 Javascript
JQuery 常用方法和事件详细介绍
Apr 18 Javascript
购物车选中得到价格实现示例
Jan 26 Javascript
javascript实现2048游戏示例
May 04 Javascript
详谈JS中实现种子随机数及作用
Jul 19 Javascript
AngularJS基础 ng-switch 指令简单示例
Aug 03 Javascript
AngularJS 所有版本下载地址
Sep 14 Javascript
bootstrap选项卡使用方法解析
Jan 11 Javascript
JS sort排序详细使用方法示例解析
Sep 27 Javascript
Vue中强制组件重新渲染的正确方法
Jan 03 Vue.js
JS获取CSS样式(style/getComputedStyle/currentStyle)
Jan 19 #Javascript
详解javascript实现自定义事件
Jan 19 #Javascript
JS拖拽组件学习使用
Jan 19 #Javascript
理解JS绑定事件
Jan 19 #Javascript
AngularJS模块学习之Anchor Scroll
Jan 19 #Javascript
jQuery unbind()方法实例详解
Jan 19 #Javascript
jQuery绑定事件监听bind和移除事件监听unbind用法实例详解
Jan 19 #Javascript
You might like
php类常量的使用详解
2013/06/08 PHP
laravel 修改.htaccess文件 重定向public的解决方法
2019/10/12 PHP
在textarea中显示html页面的javascript代码
2007/04/20 Javascript
IE和Mozilla的兼容性汇总event
2007/08/12 Javascript
javascript实现页面内关键词高亮显示代码
2014/04/03 Javascript
jquery不常用方法汇总
2015/07/26 Javascript
jquery调整表格行tr上下顺序实例讲解
2016/01/09 Javascript
Node.js连接postgreSQL并进行数据操作
2016/12/18 Javascript
Vue.use源码分析
2017/04/22 Javascript
node.js+jQuery实现用户登录注册AJAX交互
2017/04/28 jQuery
深入解析Vue 组件命名那些事
2017/07/18 Javascript
jQuery UI 实例讲解 - 日期选择器(Datepicker)
2017/09/18 jQuery
css和js实现弹出登录居中界面完整代码
2017/11/26 Javascript
bootstrap与pagehelper实现分页效果
2018/12/29 Javascript
浅谈Vue.js中如何实现自定义下拉菜单指令
2019/01/06 Javascript
微信小程序时间轴实现方法示例
2019/01/14 Javascript
深入koa-bodyparser原理解析
2019/01/16 Javascript
javascript for循环性能测试示例
2019/08/07 Javascript
Vue3 源码导读(推荐)
2019/10/14 Javascript
JS几个常用的函数和对象定义与用法示例
2020/01/15 Javascript
微信小程序图片右边加两行文字的代码
2020/04/23 Javascript
JavaScript数组类型Array相关的属性与方法详解
2020/09/08 Javascript
python获取android设备的GPS信息脚本分享
2015/03/06 Python
Python存取XML的常见方法实例分析
2017/03/21 Python
python Django框架实现web端分页呈现数据
2019/10/31 Python
pycharm工具连接mysql数据库失败问题
2020/04/01 Python
Django ModelForm组件原理及用法详解
2020/10/12 Python
localStorage 设置过期时间的方法实现
2018/12/21 HTML / CSS
HTML5+CSS3绘制锯齿状的矩形
2016/03/01 HTML / CSS
阿联酋网上花店:Ferns N Petals
2018/02/14 全球购物
个人求职信范文分享
2013/12/13 职场文书
党员违纪检讨书怎么写
2014/11/01 职场文书
2015年小学数学教研组工作总结
2015/05/21 职场文书
地道战观后感300字
2015/06/04 职场文书
迁徙的鸟观后感
2015/06/09 职场文书
Win11 22H2 2022怎么更新? 获得Win1122H22022版本升级技巧
2022/09/23 数码科技