vue双向绑定实现
Vue 双向绑定的实现原理
Vue 的双向绑定主要通过数据劫持结合发布-订阅模式实现,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。以下是具体实现方式:
数据劫持(响应式原理)
Vue 2.x 使用 Object.defineProperty:
通过递归遍历数据对象的属性,将其转换为 getter/setter,在属性被访问或修改时触发依赖收集和更新。
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`读取 ${key}`);
return val;
},
set(newVal) {
if (newVal === val) return;
console.log(`更新 ${key}`);
val = newVal;
// 触发视图更新
},
});
}
Vue 3.x 使用 Proxy:
Proxy 直接代理整个对象,无需递归遍历,性能更好且支持动态新增属性。

function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
console.log(`读取 ${key}`);
return Reflect.get(target, key);
},
set(target, key, newVal) {
if (newVal === target[key]) return true;
console.log(`更新 ${key}`);
Reflect.set(target, key, newVal);
// 触发视图更新
return true;
},
});
}
依赖收集与派发更新
Dep(依赖管理器):
每个响应式属性对应一个 Dep 实例,用于存储依赖(Watcher)。
class Dep {
constructor() {
this.subscribers = new Set();
}
depend() {
if (currentWatcher) {
this.subscribers.add(currentWatcher);
}
}
notify() {
this.subscribers.forEach(watcher => watcher.update());
}
}
Watcher(订阅者): 在组件渲染时创建,负责执行更新逻辑(如重新渲染)。

class Watcher {
constructor(updateFn) {
this.updateFn = updateFn;
this.update();
}
update() {
currentWatcher = this;
this.updateFn();
currentWatcher = null;
}
}
双向绑定的实现
模板编译:
Vue 将模板编译为渲染函数,解析 v-model 指令,生成对应的数据绑定和事件监听。
v-model 示例:
<input v-model="message">
等价于:
<input
:value="message"
@input="message = $event.target.value"
>
完整流程
- 初始化阶段: 通过数据劫持监听数据变化。
- 编译阶段: 解析模板,为每个绑定创建 Watcher。
- 依赖收集: 在首次渲染时触发
getter,将 Watcher 添加到 Dep 中。 - 更新阶段: 数据变化时触发
setter,调用Dep.notify()通知所有 Watcher 更新视图。
注意事项
- 性能优化: Vue 3.x 的
Proxy避免了 Vue 2.x 中递归遍历和无法监听新增属性的问题。 - 数组处理: Vue 2.x 需重写数组方法(如
push、pop)以实现响应式。






