JavaScript 实现观察者模式详解:从原理到代码

作者:代码拾荒

时间:2026-10-24

浏览:467

本文详细解析 JavaScript 中的观察者模式(发布-订阅模式)。通过 iPhone 预订的生活案例通俗解释其一对多依赖关系,并深入剖析 DOM 事件监听与 Vue 双向绑定中的实际应用。最后提供完整的 JavaScript 代码实现,涵盖订阅、发布、取消订阅及预订列表管理等核心逻辑,帮助开发者深入理解该设计模式。

文章目录

概述

观察者模式,亦称发布-订阅模式,属于设计模式中的行为型模式。

定义:

该模式确立了一种一对多的对象依赖关系。当被依赖对象的状态发生变动时,所有依赖于它的对象均会收到通知。

白话解释:

以在苹果专卖店购买最新款 iPhone 11 为例。由于新品刚上市且处于销售旺季,供货可能不足。若到店时无货,店员可登记你的联系方式,待到货后第一时间通知。你无需频繁到店或致电询问,因为日常工作和生活繁忙。通过留下联系方式,你只需等待通知,这种“有货即通知”的机制即为典型的观察者模式。

首先我们来分析具体构成要素:

1. 订阅方法:向店员留下联系方式即是一种消息订阅行为,确保你能及时获知 iPhone 11 到货信息。因此,我们需要一个具体的订阅方法来实现此功能。

2. 预订列表:鉴于 iPhone 11 是新机型,预订者众多。店员需维护一个预订列表以统计所有预订者的联系方式及手机版本信息。此处可将其定义为一个对象,其中 key 代表预订者联系方式,value 代表预订的手机版本信息。

3. 发布方法:当 iPhone 11 到货时,专卖店需依据预订列表统一发送消息(如“iPhone 11 到货了,大家快来抢”)。因此,专卖店需要一个发布方法来执行具体的消息推送行为。

4. 取消订阅:凡事有始有终,能订阅即可取消。若在等待 iPhone 11 期间急需手机,你转而购买了华为某款机型,此时 iPhone 11 对你的需求降低,你希望不再收到相关通知以避免打扰。因此,我们需要一个取消订阅方法来实现具体的退订行为。

观察者模式的应用场景

1、DOM 事件

作为前端开发人员,无论此前是否了解观察者模式,你很可能已经使用过它。


document.body.addEventListener('click', function() {
    console.log('hello world!');
});

这段代码是否眼熟?这是一个 DOM 事件监听示例。我们通过给 body 订阅 click 事件(click 相当于上述的订阅方法),由于浏览器无法预知你何时点击鼠标,因此在你触发 click 事件时,浏览器会调用函数向你发布通知(发布方法)。DOM 事件机制即为观察者模式的一种实现。

2、Vue 双向绑定 v-model

前端开发人员熟知 Vue 是一个采用 MVVM 模式的框架。Vue 的核心特性是双向绑定,而双向绑定的实现本质上就是观察者模式。当你绑定一个数据后(订阅方法),浏览器无法预知你何时修改数据。页面上所有绑定或依赖该数据的节点构成了一个预订列表,只有当你修改该数据值时,Vue 才会通知(发布方法)依赖该数据的方法或数据进行相应操作或刷新。

当然,观察者模式的应用远不止这两种场景。生活与业务中存在大量示例。如前文工厂模式介绍所述,设计模式是解决问题的思路而非固定公式。那么,我们该如何具体实现观察者模式呢?

观察者模式的实现


//定义商家
var merchants = {};
//定义预订列表
merchants.orderList = {};
//将增加的预定者添加到预订列表中   (订阅方法)
merchants.listen = function(id,info){
    //如果存在
    if(!this.orderList[id]){
        // (预订列表)
        this.orderList[id] = [];
    }
    // 将用户的预定的产品信息存入到数组中
    this.orderList[id].push(info);
}
//发布信息(发布方法)
merchants.publish = function(){
    var id = Array.prototype.shift.call(arguments);
    var infos = this.orderList[id];
    if(!infos || infos.length === 0){
        console.log("您还没有预定信息");
        return false;
    }

    for(var i = 0;i < infos.length;i++){
        console.log("预定成功");
        console.log("尊敬的用户:")
        infos[i].apply(this,arguments);
        console.log("到货了");
    }
}
//取消订阅  
merchants.remove = function(id,fn){
    var infos = this.orderList[id];
    if(!infos){ return false}

    if(!fn){
        console.log(123);
    }else{
        for(var i = 0;i < infos.length;i++){
            if(infos[i] === fn){
                infos.splice(i,1);
            }
        }
    }
}
let customeA = function(){
    console.log("黑色尊享版一台");
}

merchants.listen("15172103336",customeA);
merchants.remove("15172103336",customeA);
merchants.publish("15172103336");

上述代码虽稍长,但逻辑并不复杂。我们首先定义一个对象作为商家,再定义一个空对象作为预订列表,逐步实现订阅、发布及取消订阅方法。逻辑清晰,但部分语法细节需特别说明:

发布方法中的 `var id = Array.prototype.shift.call(arguments);` 语句,其作用是将 `merchants.publish("15172103336");` 调用时的第一个参数提取出来并赋值给 id,此时 id 的值为 "15172103336"。

`infos[i].apply(this,arguments);` 这一方法也不易理解。首先,infos 数组中存储的是预订者的手机号码及手机版本信息。因此,`infos[i].apply(this,arguments);` 实际上是将与 "15172103336" 对应的手机版本信息函数执行了一遍,其效果等同于 `infos[i](arguments);`。

总结

观察者模式在前端领域及现实生活中均有常见应用场景。掌握该模式有助于学习 Vue 源码等知识,其价值不仅于此,值得深入研习。简言之:"你品,你细品!" 今日付出的努力,日后终会以薪资回报你。

以上就是 JavaScript 实现观察者模式的详细内容,更多关于 JavaScript 观察者模式的资料请关注本站其它相关文章!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章