.vue 双向绑定实现原理
Vue 双向绑定实现原理
Vue 的双向绑定是通过数据劫持结合发布-订阅模式实现的,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。以下是具体实现机制:
数据劫持
Vue 2.x 使用 Object.defineProperty 对数据的 getter 和 setter 进行拦截。当访问数据时触发 getter,修改数据时触发 setter。
Object.defineProperty(obj, key, {
get() {
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
// 触发更新
}
});
Vue 3.x 改用 Proxy 实现更高效的数据劫持,支持对数组和对象深层属性的监听。

const proxy = new Proxy(obj, {
get(target, key) {
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
// 触发更新
}
});
依赖收集与发布-订阅
每个数据属性关联一个 Dep(依赖管理器),用于收集依赖(Watcher)。当数据变化时,Dep 通知所有 Watcher 更新视图。
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
模板编译
Vue 模板编译时,解析指令(如 v-model)并生成对应的 Watcher。例如 v-model 会为元素绑定 input 事件,同时监听数据变化更新 DOM。

// 简化的 v-model 实现
input.addEventListener('input', (e) => {
data.value = e.target.value;
});
new Watcher(data, 'value', (val) => {
input.value = val;
});
虚拟 DOM 与更新优化
数据变化后触发 Watcher 更新,通过虚拟 DOM 的 diff 算法计算出最小变更,再批量更新真实 DOM,提高性能。
// 简化的更新流程
updateComponent() {
const vnode = render();
patch(oldVnode, vnode);
}
双向绑定的实现示例
以下是一个极简的双向绑定实现:
function defineReactive(obj, key) {
const dep = new Dep();
let val = obj[key];
Object.defineProperty(obj, key, {
get() {
if (Dep.target) dep.addSub(Dep.target);
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify();
}
});
}
class Watcher {
constructor(vm, key, cb) {
Dep.target = this;
this.cb = cb;
vm[key]; // 触发 getter 收集依赖
Dep.target = null;
}
update() {
this.cb();
}
}
总结
Vue 双向绑定的核心是通过数据劫持监听变化,结合依赖收集和发布-订阅模式实现数据与视图的自动同步。Vue 3.x 的 Proxy 方案解决了 Vue 2.x 中无法监听新增属性和数组索引变化的问题,性能更优。






