# Events-发布订阅

TIP

Node的事件模块为events,内部实现了一个发布订阅模式

# 1、继承方式

Child.prototype = Object.create(Parent.prototype)

Child.prototype.__proto__ = Parent.prototype

Object.setPrototypeOf(Child.prototype ,Parent.prototype)

Child extends Parent

# 2、使用方法

const EventEmitter = require('events');
const util = require('util');

// 1、定义子类对象
function Personal() {}

// 2、继承父类原型方法
util.inherits(Personal, EventEmitter);

let personal = new Personal();

// 监听绑定的事件名称
personal.on('newListener',function (type) {
    console.log(type);
})

// 3、增加订阅方法
personal.on('test', function(...args) {
	console.log(...args);
});

// 4、增加发布方法
personal.emit('test', 1, 2, 3);

// 5、订阅一次的方法
personal.once('test1', function(...args) {
	console.log(...args);
});
personal.emit('test1', 1, 2, 3);
personal.emit('test1', 1, 2, 3);

// 6、关闭方法
const test2 = () => {
	console.log('test2');
}
personal.on('test2', test2);
personal.off('test2', test2)
personal.emit('test2');

# 3、原理

  • on 订阅
  • emit 发布
  • once 订阅一次
  • off 删除
// 1、定义事件类
function EventEmitter() {
	this._events = {}
}

// 2、订阅
EventEmitter.prototype.on = function(eventName, callback) {
	// 如果没有就创建一个
	if (!this._events) {
		this._events = Object.create(null);
	}
	//  当前绑定的事件 不是newListener事件就触发newListener事件
	if(eventName !== 'newListener'){
		this.emit('newListener',eventName)
	}
	// 用数组存储回调函数
	if (this._events[eventName]) {
		this._events[eventName].push(callback);
	} else {
		this._events[eventName] = [callback];
	}
}

// 发布
EventEmitter.prototype.emit = function(eventName, ...args) {
	if (!this._events) return;
	if (this._events[eventName]) {
		// 依次遍历执行回调函数
		this._events[eventName].forEach(fn => fn(...args));
	}
}

// 3、订阅一次
EventEmitter.prototype.once = function(eventName, callback) {
	// 切片编程
	const once = (...args) => {
		// 先执行原有的回调函数
		callback(...args);
		// 然后删除绑定
		this.off(eventName, once)
	}
	// 用来标识这个once是谁的
	once.l = callback;
	// 订阅
	this.on(eventName, once);
}

// 4、删除
EventEmitter.prototype.off = function(eventName, callback) {
	if (!this._events) return;
	// 过滤callback和once函数
	this._events[eventName] = this._events[eventName].filter(fn => {
		fn != callback && fn.l != callback
	})
}

module.exports = EventEmitter