JavaScript观察者模式原理与实现

凌晨两点半
凌晨两点半
发布时间:2026-10-16| 6人浏览过
原创

观察者模式定义了对象间的一对多依赖关系。本文基于JavaScript语言,以双11促销为例,演示如何实现观察者对象自动接收状态变更通知。内容涵盖核心概念、完整代码实现及优化重构。

什么是观察者模式?

观察者模式(Observer Pattern)是一种常用的设计模式。它定义了一种“一对多”的依赖关系:当一个对象(被观察者)的状态发生改变时,所有依赖于它的对象(观察者)都会收到通知并自动更新。

简单来说,该模式涉及两个主要角色:

  • 被观察者 (Observed):负责维护状态,并在状态变化时通知观察者。
  • 观察者 (Observer):注册在被观察对象上,当收到通知时执行相应的处理逻辑。

第1步:场景模拟

为了更直观地理解,我们以电商促销活动为例进行模拟:

  1. 消费者(观察者/Observer):想要在双11购买特定商品的人。他们关注商品,希望能第一时间获取降价信息。
  2. 商品(被观察者/Observed):具体的待售商品实体。
  3. 商家(发布者/Publisher):改变商品价格或库存的一方。当商家调整价格时,作为发布者的身份触发通知。

在双11当天,商家修改了商品价格(发布消息),此时已经订阅该商品的所有消费者(观察者)都会收到降价通知。

第2步:原生代码实现

下面通过一段原生JavaScript代码来实现上述逻辑。我们将创建一个名为 shopObj 的对象来管理订阅和发布行为。

// 观察者设计模式 - 基础实现
// 创建一个发布者对象,代表商家
var shopObj = {};

// 商品列表,用于存储每个商品的订阅函数 [key: []],key为商品名
shopObj.list = [];

// 订阅方法
// key: 订阅的商品型号/名称
// fn: 接收到通知后执行的回调函数
shopObj.listen = function (key, fn) {
    // 如果该商品还没有订阅者,初始化数组
    if (!this.list[key]) {
        this.list[key] = [];
    }
    // 将订阅函数存入对应商品的列表中
    this.list[key].push(fn);
};

// 发布消息方法
shopObj.publish = function (key) {
    // 获取该商品对应的所有订阅函数集合
    var fns = this.list[key];
    
    // 遍历执行所有订阅函数
    // arguments 包含 publish 调用时传入的参数(如商品信息)
    for (var i = 0, fn; fn = fns[i++]; ) {
        // apply 绑定上下文,并将后续参数传递给回调函数
        fn.apply(this, Array.prototype.slice.call(arguments, 1));
    }
};

// --- 测试用例 ---

// A用户订阅华为手机降价通知
shopObj.listen("华为", function (model, price) {
    console.log("A用户收到:" + model + "降价通知,当前价格可能是" + price);
});

// B用户也订阅华为手机
shopObj.listen("华为", function (model, price) {
    console.log("B用户收到:" + model + "降价通知");
});

// C用户订阅小米手机
shopObj.listen("小米", function (model) {
    console.log("C用户收到:" + model + "降价通知");
});

// 双11开始,商家发布消息
console.log("--- 双11商家发布消息 ---");
shopObj.publish("华为", "P30", "¥3999");
shopObj.publish("小米", "Mix4", "¥2999");

在上述代码中:
- listen(key, fn) 负责注册观察者。
- publish(key, ...args) 负责触发所有注册的回调,并将额外参数传递给它们。

第3步:代码重构与优化

原始实现中,list、listen 和 publish 都直接挂载在 shopObj 上。为了让代码更具通用性,我们可以将其封装为一个独立的工具对象 Event,并通过原型链或混合模式赋予其他对象事件能力。

// 观察者设计模式 - 重构实现
var Event = {
    // 内部存储订阅关系
    list: [],

    // 订阅方法
    listen: function (key, fn) {
        if (!this.list[key]) {
            this.list[key] = [];
        }
        this.list[key].push(fn);
    },

    // 发布方法
    publish: function (key) {
        var fns = this.list[key];
        if (!fns || fns.length === 0) return; // 增加安全性检查
        
        for (var i = 0, fn; fn = fns[i++]; ) {
            fn.apply(this, Array.prototype.slice.call(arguments, 1));
        }
    }
};

// 辅助函数:将Event对象的方法混合到目标对象中
function initEvent(obj) {
    for (let i in Event) {
        obj[i] = Event[i];
    }
}

// 创建商家对象
var shopObj = {};
initEvent(shopObj);

// 用户订阅
shopObj.listen("华为", function (model) {
    console.log("用户A获悉:" + model + "有变动");
});

shopObj.listen("小米", function (model) {
    console.log("用户B获悉:" + model + "有变动");
});

// 触发通知
shopObj.publish("华为", "Mate60");
shopObj.publish("小米", "14 Ultra");

重构后的代码逻辑更加清晰:
1. Event 对象作为一个独立的事件中心。
2. initEvent 将事件能力赋予任意对象,体现了面向对象的组合优势。
3. 增加了空值检查,防止发布未订阅的消息时报错。

总结

观察者模式是前端开发中非常基础且重要的设计模式,广泛应用于Vue/React的数据绑定、Node.js的Events模块以及DOM事件流中。通过实现一个简单的发布-订阅机制,我们可以解耦数据源与多个监听者,使代码结构更加灵活易维护。

以上就是JavaScript观察者模式原理与实现的详细内容,更多关于JavaScript设计模式与前端开发的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。