vue 3 中 reactive 对象嵌套时原型链不参与响应式追踪,所有属性必须显式定义在对象自身上才能被 proxy 拦截和响应;torefs 不处理原型属性,动态添加的原型属性也无法触发更新。

Vue 3 中 reactive 对象互相嵌套时,原型链本身不参与响应式追踪,所有“坑”都源于开发者误以为原型链上的属性能被 Proxy 拦截或继承响应性——实际上,它完全不能。
嵌套 reactive 对象不会自动代理原型属性
当你用 reactive 包裹一个对象,Vue 只对这个对象自身(own property)做 Proxy 代理。即使该对象的某个属性值本身是另一个 reactive 对象,它的 __proto__ 上的方法或数据依然不受控:
- 父对象调用子对象原型上的方法时(如
child.getName()),方法内部读取this.name会绕过 Proxy,无法触发依赖收集; - 子对象若继承自类(
class Child extends Parent),其从Parent.prototype继承的字段(如this.shared)在reactive(new Child())后修改无效; - 用
Object.create({ base: 1 })创建基对象再传入reactive(),base根本不会出现在代理的 get/set 拦截中。
嵌套解构时 toRefs 不递归处理原型链
toRefs 只转换目标对象**第一层自有属性**为 ref,且仅对当前对象自身的 key 生效:
- 如果
state.user是reactive({ name: 'a' }),而user.__proto__.age = 25,那么toRefs(state)不会把age转成响应式 ref; - 解构后使用
{ user } = toRefs(state),再访问user.value.age,这个age是原型上普通属性,修改它不会更新视图; - 想让深层属性响应,必须确保该属性落在对象自身(如
user.age = 25),再用toRef(user, 'age')单独包装。
动态添加嵌套属性时原型链加剧“失联”风险
嵌套结构中新增属性若依赖原型链,极易导致响应式断裂:
-
const form = reactive({}),随后form.detail = reactive(Object.create({ status: 'idle' }))——status在原型上,后续form.detail.status = 'done'完全无响应; - 父组件通过
ref拿到子组件暴露的reactive对象,若子组件后期往该对象原型上挂方法或属性,父组件 watch 或模板绑定均无法感知; - JSON.stringify 或第三方库遍历对象时,可能只读取自有属性,忽略原型内容,造成序列化与运行时不一致。
安全做法:切断原型依赖,显式声明自有数据
所有需要响应式的字段,必须明确写在对象自身上,而非靠 Object.create、class extends 或 assign 塞进原型:
- 嵌套对象统一用
reactive({})初始化,字段逐个赋值,避免复用原型对象; - 类实例需响应时,在构造函数内用
this.data = reactive({})隔离响应区,数据存this.data.xxx,方法可放原型但不得读写原型上的状态; - 跨层级共享逻辑,改用组合函数(
useFormState())返回toRefs,而不是让子类继承带数据的父类。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










