vue 实现响应式底层
Vue 响应式原理核心机制
Vue 的响应式系统基于 JavaScript 的 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现,通过数据劫持结合发布-订阅模式完成依赖收集与更新触发。
数据劫持实现方式
Vue 2 使用 Object.defineProperty 通过递归遍历数据对象,对每个属性设置 getter/setter 拦截操作。当数据被访问时收集依赖,数据变化时通知更新。
function defineReactive(obj, key) {
let value = obj[key]
const dep = new Dep() // 依赖收集器
Object.defineProperty(obj, key, {
get() {
if (Dep.target) {
dep.depend() // 收集当前依赖
}
return value
},
set(newVal) {
if (newVal === value) return
value = newVal
dep.notify() // 触发更新
}
})
}
Vue 3 使用 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
}
})
}
依赖收集与派发更新
Dep 类实现 每个响应式属性对应一个 Dep 实例,用于存储所有依赖该属性的 Watcher。
class Dep {
constructor() {
this.subscribers = new Set()
}
depend() {
if (Dep.target) {
this.subscribers.add(Dep.target)
}
}
notify() {
this.subscribers.forEach(watcher => watcher.update())
}
}
Watcher 机制 作为观察者,在组件渲染时创建,将自身设置为 Dep.target 以便收集依赖。
class Watcher {
constructor(vm, expOrFn) {
this.vm = vm
this.getter = parsePath(expOrFn)
this.value = this.get()
}
get() {
Dep.target = this
const value = this.getter.call(this.vm, this.vm)
Dep.target = null
return value
}
update() {
this.run()
}
}
数组响应式处理
Vue 对数组方法进行特殊处理,重写 push、pop 等变异方法,在保持原生功能的同时触发更新。
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
['push', 'pop', 'shift'].forEach(method => {
const original = arrayProto[method]
def(arrayMethods, method, function mutator(...args) {
const result = original.apply(this, args)
const ob = this.__ob__
ob.dep.notify()
return result
})
})
性能优化策略
- 异步更新队列:通过
nextTick将多次数据变更合并为单次渲染 - 虚拟 DOM 比对:减少直接 DOM 操作带来的性能损耗
- 组件级更新:精确追踪每个组件的依赖关系,避免不必要的子组件更新
响应式系统工作流程
- 初始化阶段:递归转换数据为响应式对象,建立属性与 Dep 的关联
- 依赖收集阶段:组件渲染触发 getter,将当前 Watcher 注册到对应 Dep
- 更新触发阶段:数据变更触发 setter,Dep 通知所有关联 Watcher 更新
- 批量更新阶段:通过队列机制异步执行实际 DOM 更新操作







