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) {
console.log(`更新 ${key}`);
val = newVal;
// 触发视图更新
}
},
});
}
Vue 3.x 使用 ProxyProxy 可以监听整个对象而非单个属性,解决 Vue 2.x 对数组和新增属性的监听局限:
const handler = {
get(target, key) {
console.log(`访问 ${key}`);
return Reflect.get(target, key);
},
set(target, key, value) {
if (target[key] !== value) {
console.log(`更新 ${key}`);
Reflect.set(target, key, value);
// 触发视图更新
}
return true;
},
};
const proxy = new Proxy(targetObj, handler);
依赖收集与发布订阅
-
依赖收集(Dependency Tracking)
- 在
getter中,将当前 Watcher(监听器)添加到 Dep(依赖收集器)中。 - 每个响应式属性对应一个 Dep 实例。
- 在
-
派发更新(Dependency Notifying)
- 在
setter中,通过 Dep 通知所有 Watcher 执行更新。 - Watcher 触发组件的重新渲染或计算属性更新。
- 在
双向绑定的实现
以 v-model 为例,其本质是语法糖:
<input v-model="message" />
<!-- 等价于 -->
<input
:value="message"
@input="message = $event.target.value"
/>
-
数据 → 视图
- 初始化时,
message的值通过数据劫持的getter被渲染到输入框的value。
- 初始化时,
-
视图 → 数据
- 输入框触发
input事件时,修改message的值,触发setter并通知视图更新。
- 输入框触发
虚拟 DOM 与批量更新
Vue 通过虚拟 DOM 和异步更新队列优化性能:

- 数据变化时,生成新的虚拟 DOM 树。
- 通过 Diff 算法比对差异,批量更新真实 DOM。
总结
- 数据劫持:
Object.defineProperty或Proxy监听数据变化。 - 依赖收集:
getter中收集依赖,setter中触发更新。 - 发布订阅:通过 Dep 和 Watcher 管理依赖关系。
- 双向绑定:
v-model结合:value和@input实现视图与数据的同步。






