硬核分享 | 这一次,我把 Vue3 响应式原理彻底搞懂了
大家好,我是蔓蔓。作为一个 Vue 的深度用户,之前一直都是“会用”,但总觉得心里没底。趁着最近独立开发有了些空闲时间,我终于把 Vue3 的响应式原理好好研究了一番。今天来和大家分享我的学习成果。
从 Proxy 说起
Vue3 废弃了 Vue2 的 Object.defineProperty,转而使用 Proxy。这是有本质区别的:
// Vue2 的方式 – 劫持对象的属性
Object.defineProperty(obj, 'name', {
get() { return 'Alice' },
set(newVal) { console.log('set:', newVal) }
})
// Vue3 的方式 – 劫持整个对象
const proxy = new Proxy(obj, {
get(target, key) { return Reflect.get(target, key) },
set(target, key, value) { return Reflect.set(target, key, value) }
})
Proxy 可以拦截更多操作:属性访问、赋值、删除、函数调用……而 Object.defineProperty 只能拦截 get 和 set,还不支持数组的下标拦截。
reactive 函数的核心实现
先来看我们最常用的 reactive:
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
const result = Reflect.get(target, key])
// 收集依赖 – 当访问属性时,把当前 effect 记录下来
track(target, key)
// 如果是对象,递归处理(懒代理)
return typeof result === 'object' ? reactive(result) : result
},
set(target, key, value) {
const result = Reflect.set(target, key, value)
// 触发更新 – 当属性变化时,通知所有依赖的 effect
trigger(target, key)
return result
}
})
}
依赖收集与触发
这是响应式系统最核心的部分。我用一个简单的例子来说明:
const state = reactive({ count: 0 })
effect(() => {
console.log('count:', state.count) // 这里读取了 count
})
state.count++ // 触发更新,effect 会重新执行
实现原理:
// 全局的 targetMap,存储依赖关系
const targetMap = new WeakMap()
// 收集依赖
function track(target, key) {
let depsMap = targetMap.get(target)
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()))
}
let deps = depsMap.get(key)
if (!deps) {
depsMap.set(key, (deps = new Set()))
}
// 把当前正在执行的 effect 添加进去
deps.add(activeEffect)
}
// 触发更新
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const effects = depsMap.get(key)
effects.forEach(effect => effect())
}
ref 的实现
ref 其实就是对基本类型的包装:
function ref(value) {
return {
get value() {
track(this, 'value')
return value
},
set value(newVal) {
value = newVal
trigger(this, 'value')
}
}
}
computed 的秘密
computed 本质上就是一个特殊的 effect,它有缓存能力:
function computed(getter) {
let value
let dirty = true // 标记是否需要重新计算
const effect = () => { dirty = false }
const runner = () => {
if (dirty) {
value = getter()
dirty = true
}
return value
}
// 包装成 effect
effect(() => {
runner()
})
return { get value() { return runner() } }
}
写在最后
研究完这套响应式系统,我最大的感受是:看似复杂的背后,其实是很朴素的设计模式。依赖收集、发布订阅、懒计算……这些模式组合在一起,就构成了 Vue3 强大的响应式系统。
技术应当有温度,理解原理不是为了面试吹牛,而是为了用起来更踏实。
有问题欢迎评论区交流,如果对你有帮助,点个赞再走~

![[特殊字符]DeepSeek‑Harness(DSH)小白保姆教程-171主机测评](https://www.171host.com/wp-content/uploads/2026/08/20260816085112-6a817a009aabf-220x150.png)
