最近在背八股,然后看面试题的时候发现对于vue的响应式原理,观察者模式和发布订阅者模式好像都有,但是搞不清楚,所以看了几篇文章之后,根据GPT做了总结(简单版)
目录
2. 发布-订阅模式(Publish-Subscribe Pattern)
3. Vue 的响应式系统结合了观察者模式和发布-订阅模式的特点
1. 观察者模式(Observer Pattern)
- 核心思想:对象之间通过直接引用来建立一种一对多的依赖关系。
- 机制:观察者直接订阅被观察对象(通常称为“主体”)的变化。
- 通知方式:当主体状态发生变化时,会自动通知所有观察者对象,观察者自行处理这些通知。
- 缺点:耦合性较高,因为观察者需要直接依赖被观察的对象。
观察者模式示例:
// 被观察对象(主体)
class Subject {
constructor() {
this.observers = [];
}
// 添加观察者
addObserver(observer) {
this.observers.push(observer);
}
// 通知观察者
notifyObservers() {
this.observers.forEach(observer => observer.update());
}
}
// 观察者
class Observer {
update() {
console.log('被通知了!');
}
}
// 示例
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers(); // 输出:'被通知了!' 两次
2. 发布-订阅模式(Publish-Subscribe Pattern)
- 核心思想:通过第三方(发布中心)来解耦发布者和订阅者。
- 机制:发布者和订阅者不直接联系,而是通过“事件中心”进行消息传递。
- 通知方式:发布者将消息发布到中心,中心再广播给所有订阅者。
- 优点:低耦合,发布者和订阅者彼此独立,可以动态添加订阅者,便于模块化。
发布-订阅模式示例:
// 发布-订阅中心
class EventEmitter {
constructor() {
this.events = {};
}
// 订阅
on(event, listener) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(listener);
}
// 发布
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(listener => listener(...args));
}
}
}
// 示例
const eventEmitter = new EventEmitter();
eventEmitter.on('message', (msg) => console.log('订阅者1收到消息:' + msg));
eventEmitter.on('message', (msg) => console.log('订阅者2收到消息:' + msg));
eventEmitter.emit('message', 'Hello, World!'); // 输出:两次不同订阅者收到消息
3. Vue 的响应式系统结合了观察者模式和发布-订阅模式的特点
在 Vue 中,数据的变动会触发相关视图的更新,同时组件之间的数据依赖和更新关系是自动建立的。其实现方式在 Vue 2 和 Vue 3 略有不同,但都融合了这两种模式的特性。
Vue 响应式系统的核心组成部分:
- Dep:依赖收集器。Vue 中每个响应式属性都拥有一个Dep实例。Dep 的作用相当于发布-订阅模式的事件中心,负责依赖收集和通知更新。
- Watcher:观察者。Watcher是 Vue 中的一个对象,用于跟踪数据的变化并重新渲染视图。当依赖的数据发生变化时,Watcher会被通知去更新视图。
Vue 结合两种模式的实现过程:
-
观察者模式的体现:
- Vue 的 Watcher通过依赖收集直接订阅了数据的变化。
- 当数据变化时,通过 Dep 触发 Watcher的更新,Watcher再去触发组件的重新渲染。
- 每个 Watcher知道自己依赖了哪些数据属性。
-
发布-订阅模式的体现:
- Dep 相当于一个中介,负责维护所有依赖于数据的 Watcher,并在数据变化时广播给所有 Watcher。
- 数据和视图之间的关系通过 Dep 解耦,避免了组件和数据之间的直接依赖关系,使得更新逻辑更灵活。
Vue2响应式的简单实现:
class Dep {
constructor() {
this.subscribers = new Set();
}
// 添加订阅者
depend() {
if (activeWatcher) {
this.subscribers.add(activeWatcher);
}
}
// 通知所有订阅者更新
notify() {
this.subscribers.forEach(sub => sub.update());
}
}
class Watcher {
constructor(fn) {
this.fn = fn;
activeWatcher = this; // 当前观察者
fn(); // 触发依赖收集
activeWatcher = null;
}
update() {
this.fn();
}
}
function reactive(obj) {
Object.keys(obj).forEach(key => {
let internalValue = obj[key];
const dep = new Dep();
Object.defineProperty(obj, key, {
get() {
dep.depend(); // 收集依赖
return internalValue;
},
set(newValue) {
internalValue = newValue;
dep.notify(); // 触发更新
}
});
});
return obj;
}
// 示例
let activeWatcher = null;
const data = reactive({ price: 5, quantity: 2 });
new Watcher(() => {
console.log('总价更新:', data.price * data.quantity);
});
data.price = 10; // 输出:'总价更新: 20'
一位博主的Vue2源码浅析文章:
前端 - Vue2源码-响应式原理浅析 - Vue源码分析 - SegmentFault 思否
标签:订阅,vue,Dep,观察者,模式,Watcher,Vue From: https://blog.csdn.net/shadowflies/article/details/143712548