zlx362211854 / daily-study

每日一个知识点总结,以issue的形式体现
10 stars 6 forks source link

1. js观察者模式如何实现 #1

Open zlx362211854 opened 5 years ago

zlx362211854 commented 5 years ago

观察者模式

观察者模式有几个要素:

  1. 需要将需要观察的对象存放起来
  2. 在需要的地方触发该观察者
  3. 第三观察者需要分类,同一类的观察者可监听同一个事件,监听被触发时,所有的观察者都需要被通知到。

具体实现一个观察者模式如下:

;(function(w) {
var Listen = function () {
    this.pool = new Map();
}
// 注册观察者
Listen.prototype.on = function(type, cb) {
    if (this.pool.get(type)) {
        this.pool.get(type).push(cb)
    } else {
        this.pool.set(type, [cb])
    }
}
// 触发观察者
Listen.prototype.emit = function(type, ...args) {
    if (this.pool.get(type)) {
        this.pool.get(type).forEach(listener => {
            listener.apply(type, args)
        })
    } else {
        console.log('undefined type:', type)
    }
}
// 删除观察者
Listen.prototype.remove = function(type) {
if (this.pool.get(type)) {
        this.pool.delete(type)
    } else {
        console.log('undefined type:', type)
    }
    return this;
}
w.Listen = Listen;
})(window)

上面代码里使用了es6 的Map对象来存储观察者。注册观察者的时候,每收到一个观察者注册,就按类型将他们分类存放,同一类的观察者存储在一个数组中。触发观察者的代码中,收到触发的命令后,找出触发的类型,调用所有已注册的同类的观察者。删除观察者,就将注册的所有观察者删除,return this方便链式调用

调用示例如下:

var listener = new Listen()
    listener.on('click', () => {
        console.log('clicked 1 ...')
    })
    listener.on('click', () => {
        console.log('clicked 2 ...')
    })
    listener.on('hover', () => {
        console.log('hover 1 ...')
    })
    listener.emit('click')
    listener.emit('hover')
    listener.remove('click').on('click', () => {
        console.log('click again ...')
    })
    listener.emit('click')

// clicked 1 ...
// clicked 2 ...
// hover 1 ...
// click again ...

至此,就实现了一个简单的观察者模式

goldEli commented 5 years ago

什么是观察者模式?

观察者模式简单来讲就是一对多的依赖关系,当一个对象发生改变,就会通知它的依赖者发生改变。

所以观察者模式必须要具备两个元素,即观察者被观察,观察者订阅被观察者,被观察者通知观察者,如下图:

如何实现观察者模式?

class Subject {
  observers= []
  subscribe(func) {
    this.observers.push(func)
  }
  notify(message) {
    this.observers.forEach(observer => {
      observer(message)
    })
  }
}

var s = new Subject()
var obverser1 = (message) => {console.log("我是第一个观察者:"+message)}
var obverser2 = (message) => {console.log("我是第二个观察者:"+message)}
s.subscribe(obverser1)
s.subscribe(obverser2)
s.notify("test1")
// => 我是第一个观察者:test1
// => 我是第二个观察者:test1

以上就实现了一个简单的观察者模式。

有时候可能需要多个被观察对象时,为了不创建多个对象,可以引入主题(subject),根据不同的主题通知不同的观察者。

roxy0724 commented 5 years ago

观察者模式可以说是发布-订阅模式,但略有不同,它实现了一对多的依赖关系,当某个对象发生改变时,依赖于它的对象都会得到通知和更新。二者区别在于前者无调度中心,调动方式不同。

document.body.addEventListener("click", function(){
    alert("Hello~")
}, false)
document.body.click()

以上订阅了一个在body上的click事件,当点击时触发该事件,向订阅者发布“Hello~”

SimpleSimple commented 5 years ago

什么时候用js写下数据结构和算法啊

zlx362211854 commented 5 years ago

什么时候用js写下数据结构和算法啊

欢迎提供啊,按之前issue的命名格式来就行。