vue实现双向数据绑定的原理
Vue 双向数据绑定的原理
Vue 的双向数据绑定是通过数据劫持结合发布-订阅模式实现的,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。以下是具体实现机制:
数据劫持
通过 Object.defineProperty 或 Proxy 劫持数据的 getter 和 setter,在数据变化时触发更新。Vue 2.x 使用 Object.defineProperty 递归遍历对象属性,为每个属性添加 getter/setter。
// Vue 2.x 数据劫持示例
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log('get:', val);
return val;
},
set(newVal) {
if (newVal === val) return;
console.log('set:', newVal);
val = newVal;
// 触发更新
},
});
}
Vue 3.x 改用 Proxy,直接代理整个对象,无需递归,性能更好。
// Vue 3.x 数据劫持示例
const handler = {
get(target, key) {
console.log('get:', target[key]);
return Reflect.get(target, key);
},
set(target, key, value) {
if (target[key] === value) return true;
console.log('set:', value);
Reflect.set(target, key, value);
// 触发更新
return true;
},
};
const proxy = new Proxy(target, handler);
依赖收集与发布-订阅
在 getter 中收集依赖(Watcher),在 setter 中通知依赖更新。Vue 的 Dep 类管理依赖,Watcher 是观察者,负责更新视图。
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
update() {
// 更新视图
}
}
模板编译
Vue 将模板编译为渲染函数,解析指令(如 v-model)。v-model 是语法糖,本质是 :value 绑定和 @input 事件监听的组合。
<input v-model="message">
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value">
整体流程
- 初始化阶段:劫持数据,编译模板,创建
Watcher。 - 依赖收集:渲染时触发
getter,Dep收集当前Watcher。 - 更新阶段:数据变化触发
setter,Dep通知Watcher更新视图。
对比 Vue 2.x 与 3.x
- Vue 2.x:基于
Object.defineProperty,需递归遍历对象,无法监听数组索引和length变化,需额外处理。 - Vue 3.x:基于
Proxy,支持动态新增属性,性能更优,无需手动处理数组。







