发布订阅模式在JavaScript中非常重要,可以用于模块件的通讯,DOM事件机制就是发布订阅模式的体现。接下来手动实现一个Event模块,实现以下功能

    方法名称 功能
    on(event, listener) 为指定事件添加一个监听器
    emit(event, [arg1], [arg2], […]) 按监听器的顺序执行执行每个监听器,如果事件有注册监听返回 true,否则返回 false
    once(event, listener) 为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器。
    off(event, listener) 移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。 它接受两个参数,第一个是事件名称,第二个是回调函数名称。
    listeners(event) 返回指定事件的监听器数组。
    1. class EventEmitter {
    2. constructor() {
    3. this._eventsMap = {}
    4. }
    5. /**
    6. * 添加事件监听
    7. *
    8. * @param {*} event
    9. * @param {*} listener
    10. * @param {boolean} [once=false]
    11. * @memberof EventEmitter
    12. */
    13. on(event, listener, once = false) {
    14. if (!this._eventsMap[event]) {
    15. this._eventsMap[event] = []
    16. }
    17. const listeners = this._eventsMap[event]
    18. if (!this._eventsMap[event].includes(listener)) {
    19. this._eventsMap[event].push(listener)
    20. listener.once = once
    21. }
    22. }
    23. /**
    24. * 触发事件
    25. *
    26. * @param {*} event
    27. * @param {*} args
    28. * @returns
    29. * @memberof EventEmitter
    30. */
    31. emit(event, ...args) {
    32. const listeners = this._eventsMap[event]
    33. const _this = this
    34. if (listeners && listeners.length > 0) {
    35. listeners.forEach(listener => {
    36. listener.call(_this, ...args)
    37. if (listener.once) {
    38. this.off(event, listener)
    39. }
    40. });
    41. return true
    42. }
    43. return false
    44. }
    45. /**
    46. * 添加事件监听,并只能触发一次
    47. *
    48. * @param {*} event
    49. * @param {*} listener
    50. * @memberof EventEmitter
    51. */
    52. once(event, listener) {
    53. this.on(event, listener, true)
    54. }
    55. /**
    56. * 取消事件监听
    57. *
    58. * @param {*} event
    59. * @param {*} listener
    60. * @memberof EventEmitter
    61. */
    62. off(event, listener) {
    63. if (this._eventsMap[event]) {
    64. if (!listener) {
    65. this._eventsMap[event] = []
    66. } else {
    67. this._eventsMap[event] = this._eventsMap[event].filter(_listener => _listener !== listener)
    68. }
    69. }
    70. }
    71. }