简介:
发布-订阅模式可以取代对象之间硬编码的通知机制,一个对象不用再显式地调用另外一个对象的某个接口。发布-订阅模式让两个对象松耦合地联系在一起,虽然不太清楚彼此的细节,但这不影响它们之间相互通信。当有新的订阅者出现时,发布者的代码不需要任何修改;同样发布者需要改变时,也不会影响到之前的订阅者。只要之前约定的事件名没有变化,就可以自由地改变它们。
简单实现:
class Observer {
constructor() {
this.subscribers = {}
}
on(type, fn) {
if (!Object.prototype.hasOwnProperty.call(this.subscribers, type)) {
this.subscribers[type] = [];
}
this.subscribers[type].push(fn);
}
once(type,fn){
let cb=(v)=>{
fn(v);
this.off(type,cb)
}
this.on(type,cb)
}
off(type, fn,isall=false) {
let listeners = this.subscribers[type];
if (!listeners || !listeners.length) return;
isall?this.subscribers[type]=[]:this.subscribers[type] = listeners.filter(v => v !== fn );
}
emit(type, ...args) {
let listeners = this.subscribers[type];
if (!listeners || !listeners.length) return;
listeners.forEach(fn => fn(...args));
}
}
let ob = new Observer();
let click1=function (val){ console.log('这是click1事件=>',val)}
let click2=function (val){ console.log('这是click2事件=>',val)}
ob.on('click', click1);
ob.on('click', click2);
// 每个示例运行单独注释掉即可
// 示例1: 一个事件绑定多个函数
ob.emit('click', '我点击了哦');
// 示例2: 关掉后绑定click1的不会执行 但是绑定click2的可以执行
//如removeEventListener 一样 匿名函数此种写法无法解除
// ob.off('click',click1)
// ob.emit('click', '我点击了哦');
// 示例3:解除事件绑定的所有函数
// ob.off('click',click1,true)
// ob.emit('click', '我点击了哦');
// 只执行一次的函数
// let fitF=(v)=>{console.log('我执行了fit',v)}
// ob.once('fit',fitF)
// ob.emit('fit','我执行了')
// // 下面2不会执行
// ob.emit('fit','我执行2')
为什么要使用Object.prototype.hasOwnProperty
因为js没有将hasOwnProperty作为一个敏感词,所以我们很有可能将对象的一个属性命名为hasOwnProperty,这样一来就无法再使用对象原型的 hasOwnProperty 方法来判断属性是否是来自原型链。
var foo = {
hasOwnProperty: function() { return false; },
bar: 'Here be dragons'
};
foo.hasOwnProperty('bar'); // 始终返回 false
不能使用 该对象.hasOwnProperty 这种方法,怎么来解决这个问题呢?我们需要使用原型链上真正的 hasOwnProperty 方法
({}).hasOwnProperty.call(foo, 'bar'); // true
// 或者:
Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
网友评论