JS设计模式-观察者模式

Posted 总在落幕后

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS设计模式-观察者模式相关的知识,希望对你有一定的参考价值。


前言


    

    设计模式,是一套被反复使用、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。今天小编带大家了解一下js设计模式中的观察者模式


正文



简述

    观察者模式,是定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。事实上,观察者模式处处体现在我们平时的code。如

window.addEventListener('click', function(){})

    在DOM节点上绑定过事件函数便是观察者模式的一种应用。


实现

    下面简单介绍常见的用法。


一、手动触发型

    下面是一个简单EventListener的实现:

function checkListener(listener) { if (typeof listener !== 'function') { throw new Error('listener must be a Function'); } }
class EventListener { constructor() { this.events = Object.create(null) } addEventListener(type, listener) { checkListener(listener) this.events[type] ? this.events[type].push(listener) : (this.events[type] = [listener]) } removeEventListener(type, listener) { checkListener(listener) if (!this.events) return this
let list = this.events[type] if (!list) return this if (list === listener || listener === undefined) list = undefined
let idx = list.findIndex(fun => fun === listener) if (idx !== -1) list.splice(idx, 1) return this } emit(type, ...args) { const _events = this.events if (!_events || !_events[type]) return false
const handler = _events[type] if (handler === undefined) return false for (let i = 0; i < handler.length; ++i) { handler[i].apply(this, args) } }}

      类EventListener使用ES6的class声明,其构造函数会创建一个event的空对象,用于存储事件类型(key)和相对应的事件函数(value)。


    addEventListener和removeEventListener函数都有两个参数type, listener,用于添加和删除相对应type的响应函数listener。

    emit就是我们触发某事件的函数,通过传入事件的类型,会循环调用listener函数即观察者们,并通过apply传递参数。

    

    现在,我们执行下以下代码:

const event = new EventListener()
const h1 = function () { console.log('h1 : 我被触发了')}const h2 = function (arg1, arg2// 带有参数 console.log(`h2 : 我被触发了, arg1 = ${arg1}, arg2 = ${arg2}`)}const h3 = function ({ console.log('h3 : 我被触发了')}event.addEventListener('zty', h1)event.addEventListener('zty', h2)event.addEventListener('zty', h3)
event.emit('zty'123456// 触发函数时传递函数console.log('------------------')
event.removeEventListener('zty', h3) // 删除h3观察者event.emit('zty')
console.log('------------------')console.log('event = ', event)

    在浏览器中我们可以看结果。如想象的一样,emit触发了存储events中的函数


上面我们介绍了手动触发型,下面我们讲讲自动触发的


 二、自动触发型

    话不多说上代码:

// 接收状态变化,触发每个观察者class Subject { constructor() { this.state = 0    this.observers = [] } setState(state) { this.state = state this.notify() } getState() { return this.state } attach(observer) { this.observers.push(observer) } notify() { this.observers.forEach(observer => { observer.update() }) }}
// 观察者,等待被触发class Observer { constructor(name, subject) { this.name = name this.subject = subject this.subject.attach(this) } update() {    console.log(`${this.name} update`,  `state: ${this.subject.getState()}`) }}

    类Subject中的observers存储订阅state变化的观察者数组。 进行setState操作时会触发notify函数,遍历数组中的观察者并调用他们的update方法。

    让我们看看代码的执行结果

输入代码

let s = new Subject()let o1 = new Observer('o1', s)let o2 = new Observer('o2', s)let o3 = new Observer('o3', s)
s.setState(1)
console.log('------------------')console.log('s = ', s)

输出


    结果也如想象的一样,setState的时候触发了观察者的update方法。


结束语



    观察者主要实现就是通过数组存放观察者,然后通过函数循环遍历数组调用观察者的函数。平常中我们可以看到很多使用观察者模式的例子,如node核心模块event中的EventEmitter,也就是上诉例子一;Vue中的watch和例子二主要思想差不多。

    最后,希望文章中的内容可以对大家有所帮助,欢迎讨论,感谢支持~

以上是关于JS设计模式-观察者模式的主要内容,如果未能解决你的问题,请参考以下文章

js设计模式之实现观察者模式实例代码

js设计模式-观察者模式来模拟vue的双向数据绑定

js中的观察者模式

JS实现Observable观察者模式

观察者模式(JS描述)

JS 设计模式八 -- 发布订阅者模式