vue怎么实现响应式
Vue响应式原理
Vue的响应式系统基于Object.defineProperty(Vue 2)或Proxy(Vue 3)实现,通过数据劫持和依赖收集自动更新视图。
Vue 2实现方式
数据劫持
通过Object.defineProperty重写对象的属性访问器:
function defineReactive(obj, key) {
let value = obj[key]
const dep = new Dep() // 依赖收集器
Object.defineProperty(obj, key, {
get() {
dep.depend() // 收集当前依赖
return value
},
set(newVal) {
if (newVal === value) return
value = newVal
dep.notify() // 通知更新
}
})
}
数组处理 需要特殊处理数组的变异方法:
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
const methodsToPatch = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
methodsToPatch.forEach(method => {
arrayMethods[method] = function(...args) {
const result = arrayProto[method].apply(this, args)
this.__ob__.dep.notify()
return result
}
})
Vue 3实现方式
Proxy代理 使用ES6的Proxy实现响应式:
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key) // 收集依赖
return Reflect.get(target, key)
},
set(target, key, value) {
Reflect.set(target, key, value)
trigger(target, key) // 触发更新
return true
}
})
}
Reflect API 配合Reflect实现更可靠的属性操作:
const observed = new Proxy(data, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver)
return isObject(result) ? reactive(result) : result
}
})
依赖收集系统
Watcher机制 每个组件实例对应一个watcher,在渲染过程中访问数据时会触发getter进行依赖收集:
class Watcher {
constructor(vm, expOrFn) {
this.vm = vm
this.getter = parsePath(expOrFn)
this.value = this.get()
}
get() {
pushTarget(this)
const value = this.getter.call(this.vm, this.vm)
popTarget()
return value
}
}
Dep类 管理依赖的发布订阅模式:
class Dep {
constructor() {
this.subs = []
}
depend() {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify() {
const subs = this.subs.slice()
for (let i = 0; i < subs.length; i++) {
subs[i].update()
}
}
}
响应式API对比
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 核心实现 | Object.defineProperty | Proxy |
| 数组处理 | 重写原型方法 | 原生支持 |
| 性能 | 需要递归遍历 | 惰性劫持 |
| 新属性响应 | 需要Vue.set | 自动响应 |
注意事项
- 对象属性删除需要使用
Vue.delete(Vue 2)或保持Proxy响应性(Vue 3) - 嵌套对象需要递归进行响应式处理
- 避免在data中声明未使用的属性,Vue 2无法检测属性添加
- 大型数组使用Vue 3的Proxy性能更优







