观察者模式又叫做发布订阅模式,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生改变时就会通知所有观察着对象。 它是由两类对象组成,主题和观察者,主题负责发布事件,同时观察者通过订阅这些事件来观察该主体,发布者和订阅者是完全解耦的,彼此不知道对方的存在,两者仅仅共享一个自定义事件的名称。

在Nodejs中通过EventEmitter实现了原生的对于这一模式的支持。

在JavaScript中事件监听机制就可以理解为一种观察者模式。通过onclick进行事件绑定,然后通过交互行为进行触发或者事件主动触发。

下面给出一个JS自定义的PubSub,仔细阅读下面这段代码有助于你理解观察者模式。

一、定义观察者类Pubsub

  1. /* Pubsub */
  2. function Pubsub(){
  3. //存放事件和对应的处理方法
  4. this.handles = {};
  5. }

二、实现事件订阅on

  1. //传入事件类型type和事件处理handle
  2. on: function (type, handle) {
  3. if(!this.handles[type]){
  4. this.handles[type] = [];
  5. }
  6. this.handles[type].push(handle);
  7. }

三、实现事件发布emit

  1. emit: function () {
  2. //通过传入参数获取事件类型
  3. var type = Array.prototype.shift.call(arguments);
  4. if(!this.handles[type]){
  5. return false;
  6. }
  7. for (var i = 0; i < this.handles[type].length; i++) {
  8. var handle = this.handles[type][i];
  9. //执行事件
  10. handle.apply(this, arguments);
  11. }
  12. }

需要说明的是Array.prototype.shift.call(arguments)这句代码,arguments对象是function的内置对象,可以获取到调用该方法时传入的实参数组。
shift方法取出数组中的第一个参数,就是type类型。

四、实现事件取消订阅off

  1. off: function (type, handle) {
  2. handles = this.handles[type];
  3. if(handles){
  4. if(!handle){
  5. handles.length = 0;//清空数组
  6. }else{
  7. for (var i = 0; i < handles.length; i++) {
  8. var _handle = handles[i];
  9. if(_handle === handle){
  10. handles.splice(i,1);
  11. }
  12. }
  13. }
  14. }
  15. }

完整代码:

  1. /* Pubsub */
  2. function Pubsub(){
  3. //存放事件和对应的处理方法
  4. this.handles = {};
  5. }
  6. Pubsub.prototype={
  7. //传入事件类型type和事件处理handle
  8. on: function (type, handle) {
  9. if(!this.handles[type]){
  10. this.handles[type] = [];
  11. }
  12. this.handles[type].push(handle);
  13. },
  14. emit: function () {
  15. //通过传入参数获取事件类型
  16. var type = Array.prototype.shift.call(arguments);
  17. if(!this.handles[type]){
  18. return false;
  19. }
  20. for (var i = 0; i < this.handles[type].length; i++) {
  21. var handle = this.handles[type][i];
  22. //执行事件
  23. handle.apply(this, arguments);
  24. }
  25. },
  26. off: function (type, handle) {
  27. handles = this.handles[type];
  28. if(handles){
  29. if(!handle){
  30. handles.length = 0;//清空数组
  31. }else{
  32. for (var i = 0; i < handles.length; i++) {
  33. var _handle = handles[i];
  34. if(_handle === handle){
  35. handles.splice(i,1);
  36. }
  37. }
  38. }
  39. }
  40. }
  41. }

五、测试

 
  1. var p1 = new Pubsub();
  2. p1.on('mm', function (name) {
  3. console.log('mm: '+ name);
  4. });
  5. p1.emit('mm','哈哈哈哈');
  6. console.log('===============');
  7. var p2 = new Pubsub();
  8. var fn = function (name) {
  9. console.log('mm2: '+ name);
  10. };
  11. var fn2 = function (name) {
  12. console.log('mm222: '+ name);
  13. };
  14. p2.on('mm2', fn);
  15. p2.on('mm2', fn2);
  16. p2.emit('mm2','哈2哈2哈2哈2');
  17. console.log('-------------');
  18. p2.off('mm2', fn);
  19. p2.emit('mm2','哈2哈2哈2哈2');
  20. console.log('-------------');
  21. p2.off('mm2');
  22. p2.emit('mm2','哈2哈2哈2哈2');
  23. console.log('-------------');

有关JavaScript的技术要点文章请看上海尚学堂:《JavaScript的文档对象模型DOM》;《js 大厦之JavaScript事件》;《细说JavaScript BOM》等,请多多关注。

JavaScript原生实现观察者模式的更多相关文章

  1. jQuery? 回归JavaScript原生API

    如今技术日新月异,各类框架库也是层次不穷.即便当年漫山红遍的JQuery(让开发者write less, do more,So Perfect!!)如今也有被替代的大势.但JS原生API写法依旧:并且 ...

  2. 据说每个大牛、小牛都应该有自己的库——JavaScript原生对象拓展

    在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏,一是,关于写个自己的库的想法由来 ...

  3. JavaScript原生折叠扩展收缩菜单带缓冲动画

    JavaScript原生折叠扩展收缩菜单带缓冲动画 @落雨 <div id="div_two" style="display: none;"> &l ...

  4. [转] 有趣的JavaScript原生数组函数

    在JavaScript中,可以通过两种方式创建数组,Array构造函数和 [] 便捷方式, 其中后者为首选方法.数组对象继承自Object.prototype,对数组执行typeof操作符返回‘obj ...

  5. JavaScript原生数组函数

    有趣的JavaScript原生数组函数 在JavaScript中,可以通过两种方式创建数组,构造函数和数组直接量, 其中后者为首选方法.数组对象继承自Object.prototype,对数组执行typ ...

  6. JavaScript原生对象拓展

    JavaScript原生对象拓展 在据说每个大牛.小牛都应该有自己的库——框架篇中我扬言要做个小牛,没想到一天没更新,小伙儿伴们就戏谑的问我,油哥是不是要太监了?其实事情是这个样子的,这不是太监的节奏 ...

  7. 使用 javascript 来实现 观察者模式

    以[猫叫.老鼠跑.主人醒]为例子,使用 javascript 来实现 观察者模式 (有在线演示) 2013-06-24 08:35 by 金色海洋(jyk)阳光男孩, 572 阅读, 4 评论, 收藏 ...

  8. JavaScript原生Array常用方法

    JavaScript原生Array常用方法 在入门Vue时, 列表渲染一节中提到数组的变异方法, 其中包括push(), pop(), shift(), unshift(), splice(), so ...

  9. jQuery 事件绑定 和 JavaScript 原生事件绑定

    总结一下:jQuery 事件绑定 和 JavaScript 原生事件绑定 及 区别 jQuery 事件绑定 jQuery 中提供了四种事件监听绑定方式,分别是 bind.live.delegate.o ...

随机推荐

  1. linklist和arraylist区别

    ArrayList更适合读取数据,linkedList更多的时候添加或删除数据.

  2. kubernetes + istio进行流量管理

    实验目的: 本文介绍如何通过istio实现域名访问k8s部署的nginx服务 前提: 已经安装了kubernetes的服务器 了解 kubernetes 基本命令如何使用 (kubectl creat ...

  3. python3 requestsGET请求传参

    GET方式传参方式一: import requests url = 'http://www.baidu.com/s?page=2' # 使用?携带参数 r = requests.get(url) pr ...

  4. .Net 配置的简陋解决方案

    公司是做CS产品的, 最近分配给我一个活, 要求:     1. 公司程序启动时, 检测是否有配置文件, 没有的话则按默认值创建一个     2. 配置文件要加密, 不能让客户随便看到里面的参数   ...

  5. 分享一个可以把 iOS/Android 应用的下载链接合成一个二维码的工具

    芝麻二维码官网:https://www.hotapp.cn 1.在iOS系统设备扫描时 如果是微信扫描,因为第一步里使用了中间页面,此时无法直接跳转到App Store了,所以需要给出提示页面,提示用 ...

  6. 奇异值分解(SVD)

    首先说明一下特征值:设A是n阶方阵,如果存在 λ 和n维非零向量X,使 AX = λX ,则 λ 称为方阵A的一个特征值,X为方阵A对应于或属于特征值 λ 的一个特征向量. AX = λX 的过程是一 ...

  7. 关于tomcat7配置maxPostSize=“0”时,后台无法接收前台参数的问题

    Post提交参数时,如果参数值的长度太长,后台通过Map<String, String[]> requestParameterMap=request.getParameterMap();获 ...

  8. Maven学习 七 Maven项目创建(2)war项目

    一.web项目的目录结构 如果手动创建一个java  web项目,其基本的目录结构包括:METE-INF,WEB-INF,以及WEB-INF下必须包含一个web.xml文件 二.使用Maven创建wa ...

  9. 人力资源项目中 add_account.php

    add_account.php ( 文件浏览 ) <?phpinclude('db_con.php');   if(isset($_POST['save'])) {    $employee_i ...

  10. 《Linux就该这么学》第十一天课程

     防火墙常用的一些命令参数 原创地址:https://www.linuxprobe.com/chapter-08.html firewalld中常用的区域名称及策略规则 区域 默认规则策略 trust ...