Vue 3嵌套Proxy是按需递归、惰性触发的响应式机制:访问时才对嵌套对象调用reactive生成新Proxy,避免Vue 2初始化全量遍历的性能浪费;ref包装嵌套对象时其.value仍走相同惰性代理逻辑。

Vue 3 的嵌套 Proxy 代理不是“一层套一层”的固定结构,而是一种按需递归、惰性触发的响应式机制:只有当访问到某个嵌套对象时,它才会被自动 reactive 包装,生成新的 Proxy 实例。
为什么需要嵌套代理?
响应式必须覆盖所有可能被读写的路径。比如 user.profile.address.city,如果 profile 或 address 没有被代理,那么对 city 的修改就无法触发视图更新。
Vue 2 用 Object.defineProperty 实现时,必须在初始化阶段就递归遍历整个对象树,哪怕某些深层属性从不被使用——这带来明显性能开销和内存浪费。
Vue 3 改用 Proxy 后,只在 get 拦截器中判断返回值是否为对象,是则调用 reactive() 包装并返回新代理,真正做到了“用到才代理”。
立即学习“前端免费学习笔记(深入)”;
嵌套代理如何触发?
关键在 get 拦截器中的惰性处理逻辑:
- 当读取
obj.nested时,Reflect.get(obj, 'nested')返回原始子对象 - Proxy 的
get方法检测到该值是普通对象(且非 null),立即调用reactive(nested) - 返回的是一个全新 Proxy 实例,后续对它的任何操作(如
nested.name)都会进入另一轮拦截 - 若该子对象已被代理过,则直接复用已有代理,避免重复创建
嵌套代理的实际表现
你不需要手动写多层 reactive,Vue 内部已封装好递归逻辑:
const state = reactive({
user: {
profile: {
name: 'Alice',
settings: { theme: 'dark' }
}
}
})
此时:
-
state.user是一个 Proxy -
state.user.profile是另一个 Proxy(首次访问时创建) -
state.user.profile.settings同样是独立 Proxy - 任意层级的变更(如
state.user.profile.settings.theme = 'light')都会精准触发对应依赖更新
ref 与嵌套对象的关系
ref 本质是包装基本类型或浅层对象的工具,其 .value 若为对象,内部仍会走 reactive 流程:
-
const count = ref(1)→count是 ref 对象,count.value是原始数字 -
const obj = ref({ a: { b: 1 } })→obj.value被自动reactive,其中a在首次访问时再惰性代理 - 所以
ref+ 嵌套对象,最终仍是 Proxy 嵌套 Proxy 的结构,只是入口不同


















