在 JS 中,事件处理函数的绑定 addEventListener
就是发布订阅的模式。
addEventListener 由 EventTarget 对象提供。
方式
例子
var salesOffices = {}; // 售楼部
salesOffices.clientList = []; // 花名册
salesOffices.listen = function(fn) {
this.clientList.push(fn);
}
salesOffices.trigger = function() {
for(var i = 0; i < this.clientList.length; i++) {
var fn = this.clientlist[i];
fn.apply(this, arguments);
}
}
salesOffices.listen(function(price, square) {
console.log('zhangsan', price, square);
});
salesOffices.listen(function(price, square) {
console.log('zhaosi', price, square);
});
setTimeout(() => {
salesOffices.trigger(2000, 80);
salesOffices.trigger(3000, 110);
})
会出现一个问题,zhangsan 只关注价格 2000 以下的,zhaosi 只关注价格 3000 以上的。所以要增加一个标识来区分。
var salesOffices = {}; // 售楼部
salesOffices.clientList = []; // 花名册
salesOffices.listen = function(key, fn) {
if(!this.clientList[key]) {
this.clientList[key] = [];
}
this.clientList[key].push(fn);
}
salesOffices.trigger = function() {
var key = Array.prototype.shift.call(arguments),
fns = this.clientList[key];
for(var i = 0; i < this.fns.length; i++) {
var fn = this.clientlist[i];
fn.apply(this, arguments);
}
}
salesOffices.remove = function(key, fn) {
var fns = this.clientList[key];
if(!fns){
return false;
}
for(var i = 0; i < fns.length; i++) {
var _fn = fns[i];
if(_fn === fn) {
fns.splice(i, 1);
}
}
}
salesOffices.listen('2000meter', function(price, square) {
console.log('zhangsan', price, square);
});
salesOffices.listen('3000meter', function(price, square) {
console.log('zhaosi', price, square);
});
setTimeout(() => {
salesOffices.trigger('2000meter', 2000, 80);
salesOffices.trigger('3000meter', 3000, 110);
})
实现
// 订阅者
class Subscriber {
constructor() {
this.publishers = [];
}
// 订阅发布者
subscribe(publisher) {
this.publishers.push(publisher);
}
// 通知
notify() {
this.publishers.forEach(publisher => {
publisher.update();
})
}
}
// 发布者
class Publisher {
constructor(callback) {
this.callback = callback;
}
update() {
this.callback();
}
}
// 创建订阅者
const sub = new Subscriber();
// 创建发布者
const publisher1 = new Publisher(() => console.log('Publisher1'));
const publisher2 = new Publisher(() => console.log('Publisher2'));
// 订阅发布者
sub.subscribe(publisher1);
sub.subscribe(publisher2);
// 触发通知
sub.notify();