Vue 双向绑定的原理经历了从 Vue 2 的 Object.defineProperty 到 Vue 3 的 Proxy 的演进,以下是详细解析:
Vue 2 双向绑定原理(基于 Object.defineProperty)
核心:发布-订阅模式 + 数据劫持
// 1. 数据劫持:遍历对象属性,转为 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, '新值:', newVal)
val = newVal
}
})
}
v-model 的实现
<!-- 模板 -->
<input v-model="message">
<!-- 编译为 -->
<input
:value="message"
@input="message = $event.target.value">
Vue 3 双向绑定原理(基于 Proxy)
核心优势
- 性能更好:Proxy 是语言级别支持,无递归遍历开销
- 功能更强:支持数组索引修改、对象新增属性等
- 内存更优:惰性代理,按需响应
// 1. 响应式核心
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
// 依赖收集
track(target, key)
return typeof res === 'object' ? reactive(res) : res
},
set(target, key, value, receiver) {
const oldValue = target[key]
const result = Reflect.set(target, key, value, receiver)
if (oldValue !== value) {
// 触发更新
trigger(target, key)
}
return result
}
})
}
完整工作流程
1. 初始化阶段
模板编译 → 创建响应式数据 → 渲染组件 → 建立依赖关系
2. 数据更新阶段
用户输入 → 触发 setter → 通知 Watcher/Effect →
虚拟DOM Diff → 更新真实DOM
Vue 2 vs Vue 3 实现对比
| 特性 | Vue 2 (Object.defineProperty) | Vue 3 (Proxy) |
|---|---|---|
| 数组监听 | 需重写数组方法(push/pop等) | 原生支持 |
| 新增属性 | 需用 Vue.set() | 自动响应 |
| 性能 | 初始化递归遍历所有属性 | 惰性代理 |
| 嵌套对象 | 递归深度遍历 | 按需代理 |
| 兼容性 | IE9+ | IE 不支持 |
总结
Vue 双向绑定的本质是 数据变化驱动视图更新,视图交互更新数据 的闭环。其演进体现了前端框架对性能、开发体验、功能的不断追求。选择实现方案时需考虑:
- 项目规模:大型项目推荐 Vue 3 + Composition API
- 兼容需求:需兼容 IE 则用 Vue 2
- 性能要求:高频更新场景可用 Proxy 优势