JavaScript响应式编程的核心目标是当数据发生变化时,自动触发依赖该数据的逻辑执行,而观察者模式正是实现这一能力的经典设计模式,它通过定义对象间的一对多依赖关系,让多个观察者对象同时监听某一个主题对象的状态变化。

观察者模式的核心角色
观察者模式主要包含两个核心角色,二者分工明确共同完成状态变化的监听与通知:
- 主题(Subject):被观察的对象,负责管理所有的观察者,当自身状态发生变化时,通知所有关联的观察者。
- 观察者(Observer):监听主题状态变化的对象,当收到主题的通知时,执行自身预设的更新逻辑。
基础观察者模式的实现
我们可以先实现一个通用的观察者类,包含添加观察者、移除观察者、通知观察者三个核心方法,代码如下:
// 主题类
class Subject {
constructor() {
// 存储所有观察者
this.observers = [];
}
// 添加观察者
addObserver(observer) {
if (typeof observer.update === 'function') {
this.observers.push(observer);
} else {
throw new Error('观察者必须包含update方法');
}
}
// 移除观察者
removeObserver(observer) {
this.observers = this.observers.filter(item => item !== observer);
}
// 通知所有观察者
notify(data) {
this.observers.forEach(observer => {
observer.update(data);
});
}
}
// 基础观察者类
class Observer {
constructor(name) {
this.name = name;
}
// 更新方法,接收主题传递的数据
update(data) {
console.log(`${this.name}收到通知,数据变化为:${data}`);
}
}
结合响应式编程实现数据联动
在响应式场景中,我们通常希望数据被修改时自动触发通知,因此可以对数据进行代理,在setter中触发主题的通知逻辑,实现数据变化到逻辑执行的自动联动:
// 创建响应式数据函数
function reactive(data) {
const subject = new Subject();
// 创建数据代理
const proxy = new Proxy(data, {
set(target, key, value) {
const oldValue = target[key];
target[key] = value;
// 数据变化时通知所有观察者
subject.notify({
key,
oldValue,
newValue: value
});
return true;
}
});
// 给代理对象挂载添加观察者的方法
proxy.$watch = function(observer) {
subject.addObserver(observer);
};
return proxy;
}
// 使用示例
const userData = reactive({
name: '张三',
age: 20
});
// 创建两个观察者
const observer1 = new Observer('观察者1');
const observer2 = new Observer('观察者2');
// 添加观察者
userData.$watch(observer1);
userData.$watch(observer2);
// 修改数据,自动触发通知
userData.age = 21;
// 控制台输出:
// 观察者1收到通知,数据变化为:[object Object]
// 观察者2收到通知,数据变化为:[object Object]
实际应用场景
观察者模式结合响应式编程在实际开发中有很多应用场景:
- 前端状态管理:比如Vue的响应式系统中,依赖收集就是观察者模式的一种实现,数据变化后通知所有依赖该数据的组件更新。
- 事件总线:跨组件通信时,可以搭建一个主题作为事件总线,组件订阅事件对应添加观察者,触发事件对应通知观察者。
- 数据监听:需要监听某个数据变化执行多个后续逻辑时,不需要把逻辑硬编码在数据修改的地方,通过添加观察者即可扩展。
注意事项
使用观察者模式时需要注意避免内存泄漏,当观察者不再需要时,要及时调用移除观察者的方法,防止主题一直持有观察者的引用。另外如果通知逻辑执行耗时较长,可以考虑将通知改为异步执行,避免阻塞主线程。
JavaScript响应式编程观察者模式数据联动修改时间:2026-06-18 17:36:15