vue 3 的 ref 本质是通过 object.defineproperty 劫持 .value 的读写实现响应式,内部用 _value 存值,getter 中 track 收集依赖,setter 中 trigger 触发更新,并借助 weakmap 和 activeeffect 管理依赖关系。

Vue 3 的 ref 本质是一个带响应式能力的包裹对象,核心在于:用 Object.defineProperty(或 Proxy)劫持 .value 的读写,并在读取时收集依赖、写入时触发更新。
ref 的基本结构与响应式原理
一个最小可用的 ref 需要满足三点:能访问 .value、读取时记录当前副作用函数(effect)、赋值时通知所有依赖重新执行。它不直接代理原始值,而是把值存在内部属性上,并通过 get/set 控制访问路径。
- 内部维护一个私有变量(如
_value)存储真实数据 - 用
Object.defineProperty为ref对象定义value的 getter/setter - getter 中调用依赖收集函数(
track),setter 中触发更新(trigger)
实现 track 和 trigger 机制
依赖收集和触发需要一个全局“依赖池”——通常用 WeakMap 映射响应式对象到依赖集合(Set),再配合一个运行中的 effect 栈来确定当前谁在读取。
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 定义
activeEffect全局变量,指向当前正在执行的副作用函数 -
track(target, key):若activeEffect存在,将它添加到target对应key的依赖集合中 -
trigger(target, key):取出该key下所有 effect,依次执行 - 使用
WeakMap<any map symbol set>>></any>存储依赖关系,避免内存泄漏
写出可运行的 ref 函数
下面是一个精简但可实际运行的 ref 实现(基于 Object.defineProperty,兼容性更好):
const targetMap = new WeakMap()
let activeEffect = null
function track(target, key) {
if (!activeEffect) return
let depsMap = targetMap.get(target)
if (!depsMap) {
depsMap = new Map()
targetMap.set(target, depsMap)
}
let deps = depsMap.get(key)
if (!deps) {
deps = new Set()
depsMap.set(key, deps)
}
deps.add(activeEffect)
}
function trigger(target, key) {
const depsMap = targetMap.get(target)
if (!depsMap) return
const deps = depsMap.get(key)
if (deps) {
deps.forEach(effect => effect())
}
}
function ref(initialValue) {
const refObj = {
_value: initialValue
}
Object.defineProperty(refObj, 'value', {
get() {
track(refObj, 'value')
return refObj._value
},
set(newVal) {
if (newVal !== refObj._value) {
refObj._value = newVal
trigger(refObj, 'value')
}
}
})
return refObj
}
// 使用示例:
const count = ref(0)
function effect(fn) {
activeEffect = fn
fn()
activeEffect = null
}
effect(() => {
console.log('count is:', count.value) // 初次执行,触发 track
})
count.value = 1 // 触发 trigger,重新执行 effect
注意事项与局限性
这个简易版 ref 能跑通基础流程,但离 Vue 生产级实现还有距离:
- 不支持嵌套对象或数组的深层响应(
reactive才负责这个) - 未处理
null/undefined的value访问边界情况 - 没有做 effect 清理(如依赖被移除后自动从集合中删除)
- 多个 effect 嵌套时缺少栈管理,可能造成依赖错乱
- 未兼容
readonly、shallowRef等变体
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










