ref分两种实现:原始值用refimpl类封装+value访问器,对象则转为reactive代理;均依赖track/trigger依赖系统,通过weakmap和activeeffect实现响应式追踪与触发。

ref 并不总是用 Proxy,只有当传入的是对象或数组这类引用类型时,内部才会调用 reactive 做 Proxy 代理;而 string、number、boolean 等原始值,则靠 class RefImpl 的 getter/setter 实现响应式。所以“手写 ref”必须分两种路径处理。
原始值的 ref:靠类封装 + 属性访问器
原始值不能被 Proxy 直接代理(Proxy 只能代理对象),所以 Vue3 的 ref 把值包进一个对象里,暴露 .value 属性,并在它的 get/set 上做手脚:
- get value 时触发
track(this, 'value'),把当前副作用函数(如组件 render)记为依赖 - set value 时先比对新旧值,不同则更新内部
_rawValue和_value,再调用trigger(this, 'value')通知更新 - 如果新值是对象,还会递归调用
reactive转成响应式,保证深层嵌套也生效
引用值的 ref:内部转 reactive + Proxy 代理
当你写 ref({ a: 1 }),ref 构造函数会识别出这是对象,直接返回 reactive(obj) 的结果(但额外打上 __v_isRef: true 标记):
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
- 实际代理行为由
reactive完成:new Proxy(target, { get, set, … }) - get 拦截里调用
track(target, key)收集依赖;如果是嵌套对象,自动递归reactive - set 拦截里用
Reflect.set更新值,再trigger(target, key)通知所有依赖 - 已代理过的对象缓存在 WeakMap 中,避免重复代理和无限递归
关键配套:track / trigger 依赖系统
ref 和 reactive 都依赖同一套依赖追踪机制,核心是两个 Map:
-
targetMap: WeakMap<target map set>>></target>—— 记录每个对象每个属性对应哪些副作用函数 -
activeEffect: EffectFunction | null—— 全局暂存当前正在执行的副作用(比如 effect(() => {...})) -
track()在 get 时运行:若activeEffect存在,就把它加进targetMap.get(target)?.get(key)的集合里 -
trigger()在 set 时运行:取出对应集合,逐个执行 effect 函数
简易可运行代码骨架
下面是最小闭环实现(不含 readonly/shallow 等扩展):
let activeEffect = null
const targetMap = new WeakMap()
function track(target, key) {
if (!activeEffect) return
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()))
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 reactive(target) {
if (typeof target !== 'object' || target === null) return target
const existingProxy = toProxy.get(target)
if (existingProxy) return existingProxy
const proxy = new Proxy(target, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver)
track(target, key)
return typeof res === 'object' && res !== null ? 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
}
})
toProxy.set(target, proxy)
return proxy
}
const toProxy = new WeakMap()
class RefImpl {
constructor(rawValue) {
this.__v_isRef = true
this._rawValue = rawValue
this._value = typeof rawValue === 'object' && rawValue !== null
? reactive(rawValue)
: rawValue
}
get value() {
track(this, 'value')
return this._value
}
set value(newValue) {
if (newValue !== this._value) {
this._rawValue = newValue
this._value = typeof newValue === 'object' && newValue !== null
? reactive(newValue)
: newValue
trigger(this, 'value')
}
}
}
function ref(rawValue) {
return new RefImpl(rawValue)
}
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









