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

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

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

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

一、定义观察者类Pubsub

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

二、实现事件订阅on

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

三、实现事件发布emit

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

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

四、实现事件取消订阅off

off: function (type, handle) {
handles = this.handles[type];
if(handles){
if(!handle){
handles.length = 0;//清空数组
}else{
for (var i = 0; i < handles.length; i++) {
var _handle = handles[i];
if(_handle === handle){
handles.splice(i,1);
}
}
}
}
}

完整代码:

/* Pubsub */
function Pubsub(){
//存放事件和对应的处理方法
this.handles = {};
}
Pubsub.prototype={
//传入事件类型type和事件处理handle
on: function (type, handle) {
if(!this.handles[type]){
this.handles[type] = [];
}
this.handles[type].push(handle);
},
emit: function () {
//通过传入参数获取事件类型
var type = Array.prototype.shift.call(arguments);
if(!this.handles[type]){
return false;
}
for (var i = 0; i < this.handles[type].length; i++) {
var handle = this.handles[type][i];
//执行事件
handle.apply(this, arguments);
}
},
off: function (type, handle) {
handles = this.handles[type];
if(handles){
if(!handle){
handles.length = 0;//清空数组
}else{
for (var i = 0; i < handles.length; i++) {
var _handle = handles[i];
if(_handle === handle){
handles.splice(i,1);
}
}
}
}
}
}

五、测试

 
var p1 = new Pubsub();
p1.on('mm', function (name) {
console.log('mm: '+ name);
});
p1.emit('mm','哈哈哈哈');
console.log('===============');
var p2 = new Pubsub();
var fn = function (name) {
console.log('mm2: '+ name);
};
var fn2 = function (name) {
console.log('mm222: '+ name);
};
p2.on('mm2', fn);
p2.on('mm2', fn2);
p2.emit('mm2','哈2哈2哈2哈2');
console.log('-------------');
p2.off('mm2', fn);
p2.emit('mm2','哈2哈2哈2哈2');
console.log('-------------');
p2.off('mm2');
p2.emit('mm2','哈2哈2哈2哈2');
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. 《AlwaysRun!》第一次作业:团队亮相

    项目 内容 这个作业属于哪个课程 2016级软件工程(西北师范大学) 这个作业的要求在哪里 实验五  团队作业1:软件研发团队组建 团队名称 Always Run! 作业学习目标 熟悉软件的开发流程与 ...

  2. jna调用c++的dll

    import java.util.ArrayList; import java.util.List; import com.sun.jna.Structure; public class MyStru ...

  3. $.ajax()参数详解

    来自于<锋利的jQuery(第2版)>. 参数 类型 说明 accepts Map 内容类型发送请求头,告诉服务器什么样的响应会接受返回. 如果accepts设置需要修改,推荐在$.aja ...

  4. java实验环境搭建,eclise下载与使用

    一.1.官方下载地址:http://www.oracle.com/technetwork/java/javase/downloads/index.html 下载后安装,默认安装即可. 2.在 wind ...

  5. Centos7 安装可视化图形

    因为安装的Centos7最小安装包,虚拟机没有可视化界面,可以采用下列命令,安装可视化界面. init id::initdefault: yum install -y libdevmapper* yu ...

  6. 配置Linux客户端使用socks5代理上网

    配置Linux客户端使用socks5代理上网   背景 有访问google或者其他海外网站需求的同学可能大都用过或者听过ss,在Windows.Mac.Android.IOS都有现成可用的客户端来协助 ...

  7. Python 的 14 张思维导图汇总

    本文主要涵盖了 Python 编程的核心知识(暂不包括标准库及第三方库,后续会发布相应专题的文章). 首先,按顺序依次展示了以下内容的一系列思维导图:基础知识,数据类型(数字,字符串,列表,元组,字典 ...

  8. [并查集][NOIP2015]信息传递

    信息传递 题目描述 有 N 个同学( 编号为 1 到 N) 正在玩一个信息传递的游戏. 在游戏里每人都有一个固定的信息传递对象, 其中,编号为i的同学的信息传递对象是编号为ti的同学. 游戏开始时, ...

  9. 八、pyqt5按钮类控件——QPushButton、QRadioButton、QCheckBox

    pyqt5中常用的按钮类控件有QPushButton.QRadioButton.QCheckBox.QToolButton等.这些按钮类的基类都是QAbstracButton类.所以这些类有部分方法是 ...

  10. 【机器学习】K均值算法(II)

    k聚类算法中如何选择初始化聚类中心所在的位置. 在选择聚类中心时候,如果选择初始化位置不合适,可能不能得出我们想要的局部最优解. 而是会出现一下情况: 为了解决这个问题,我们通常的做法是: 我们选取K ...