JavaScript原生实现观察者模式(发布订阅模式)详解

作者:木棉时间:2026-10-22 10:43:52浏览:463

本文详解JavaScript中观察者模式(发布订阅模式)的实现原理。通过自定义PubSub类,演示如何定义观察者、实现事件订阅on、发布emit及取消订阅off方法。结合Nodejs原生EventEmitter与DOM事件机制,提供完整代码示例与测试用例,帮助理解一对多关系及解耦特性。

观察者模式原理与定义

观察者模式,亦称发布订阅模式,定义了一种一对多的依赖关系。在此模式中,多个观察者对象同时监听一个主题对象。当主题对象的状态发生变化时,会自动通知所有注册的观察者。该模式由主题和观察者两类对象构成:主题负责发布事件,观察者通过订阅事件来监控主题。发布者与订阅者之间完全解耦,彼此无需知晓对方的存在,仅通过共享自定义事件名称进行交互。

在Node.js环境中,EventEmitter类已原生提供了对该模式的支持。

在浏览器端的JavaScript中,事件监听机制本质上也是一种观察者模式的应用。开发者可以通过onclick等属性进行事件绑定,随后由交互行为或主动触发来执行相应逻辑。

JavaScript原生PubSub实现

下文将展示一个自定义的PubSub实现,仔细研读该代码有助于深入理解观察者模式的核心机制。

定义观察者类Pubsub

第一步:定义观察者类Pubsub


/* Pubsub */
 function Pubsub(){
  //存放事件和对应的处理方法
 this.handles = {};
 }

实现事件订阅on

第二步:实现事件订阅方法on


//传入事件类型type和事件处理handle
 on: function (type, handle) {
  if(!this.handles[type]){
   this.handles[type] = [];
  }
  this.handles[type].push(handle);
 }

实现事件发布emit

第三步:实现事件发布方法emit


emit: function () {
  //通过传入参数获取事件类型
 var type = Array.prototype.shift.call(arguments);
  if(!this.handles[type]){
   return false;
  }
 for (var i = 0; i < this.handles[type].length; i++) {
   var handle = this.handles[type][i];
   //执行事件
  handle.apply(this, arguments);
  }
 }

需要特别说明的是代码中使用的Array.prototype.shift.call(arguments)。arguments是函数的内置对象,用于获取调用该方法时传入的实参数组。

shift方法的作用是取出数组中的第一个参数,此处即为事件类型type。

实现事件取消订阅off

第四步:实现事件取消订阅方法off


off: function (type, handle) {
  handles = this.handles[type];
  if(handles){
   if(!handle){
    handles.length = 0;//清空数组
  }else{
    for (var i = 0; i < handles.length; i++) {
     var _handle = handles[i];
     if(_handle === handle){
      handles.splice(i,1);
     }
    }
   }
  }
 }

以下是PubSub类的完整代码实现。


/* Pubsub */
 function Pubsub(){
  //存放事件和对应的处理方法
 this.handles = {};
 }
 Pubsub.prototype={
  //传入事件类型type和事件处理handle
  on: function (type, handle) {
   if(!this.handles[type]){
    this.handles[type] = [];
   }
   this.handles[type].push(handle);
  },
  emit: function () {
   //通过传入参数获取事件类型
  var type = Array.prototype.shift.call(arguments);
   if(!this.handles[type]){
    return false;
   }
 for (var i = 0; i < this.handles[type].length; i++) {
    var handle = this.handles[type][i];
    //执行事件
   handle.apply(this, arguments);
   }
  },
  off: function (type, handle) {
   handles = this.handles[type];
   if(handles){
    if(!handle){
     handles.length = 0;//清空数组
   }else{
 for (var i = 0; i < handles.length; i++) {
      var _handle = handles[i];
      if(_handle === handle){
       handles.splice(i,1);
      }
     }
    }
   }
  }
 }

测试用例验证

第五步:测试用例验证


var p1 = new Pubsub();
 p1.on('mm', function (name) {
 console.log('mm: '+ name);
 });
 p1.emit('mm','哈哈哈哈');
console.log('===============');
 var p2 = new Pubsub();
 var fn = function (name) {
 console.log('mm2: '+ name);
 };
 var fn2 = function (name) {
 console.log('mm222: '+ name);
 };
 p2.on('mm2', fn);
 p2.on('mm2', fn2);
 p2.emit('mm2','哈2哈2哈2哈2');
 console.log('-------------');
p2.off('mm2', fn);
 p2.emit('mm2','哈2哈2哈2哈2');
 console.log('-------------');
p2.off('mm2');
 p2.emit('mm2','哈2哈2哈2哈2');
 console.log('-------------');

观察者模式原理与定义

以上即为JavaScript原生实现观察者模式的完整示例,供参考学习。

作者最新文章