面试中经常出现问到如何实现JS 发布者、订阅者模式。下面是ES5实现发布订阅模式。
1、直接上代码。
function EventEmitter() {
this.events = {};
};
// 订阅者
EventEmitter.prototype.on = function(ename, callback) {
if (!this.events[ename]) {
// 初始化创建订阅,一个订阅名可以创建多个时间函数
this.events[ename] = [callback];
} else {
// 订阅已存在,push指定订阅名称尾部
this.events[ename].push(callback);
}
}
// 发布者
EventEmitter.prototype.emit = function(ename) {
// 遍历执行订阅名称下的所有订阅者事件
this.events[ename] && this.events[ename].forEach(cb => {
// 执行订阅者函数
cb();
});
}
// 发布者
EventEmitter.prototype.off = function(ename, callback) {
if (this.events[ename]) {
// this.events[ename] && this.events[ename].filter(cb => cb != callback)
// console.log('this.events', this.events)
const targetIndex = this.events[ename].findIndex(cb => cb === callback)
if (targetIndex !== -1) {
this.events[ename].splice(targetIndex, 1)
}
if (this.events[ename].length === 0) {
delete this.events[ename]
}
}
}
// 只执行一次订阅发布,然后移除
EventEmitter.prototype.once = function(ename, callback) {
var that = this;
var fn = function() {
callback();
that.off(ename, fn);
}
this.on(ename, fn);
}
// 实例化构造函数
var em = new EventEmitter();
em.on("work", function() {
console.log('work,订阅发布成功');
});
var makeOnce = function() {
console.log("money,移除");
}
em.on("money", makeOnce);
em.once("love", function() {
console.log("love,仅一次");
});
em.emit("work");
em.off("money", makeOnce);
em.emit("money"); // 移除后,无法发布
em.emit("love");
em.emit("love"); // 只执行一次,再次将不再执行
2、如下是打印结果