Proxy 相比 Object.defineProperty 解决什么?
先理解原理和示例,再练习完整口述与追问。
回答要点
Proxy 可以拦截对象多种操作,使对象属性新增、删除等更容易纳入响应式。读取代理时收集依赖,写入时触发更新;直接修改原始对象绕过代理仍可能不触发。
原理拆解
Object.defineProperty 拦截单个属性访问,Proxy 可拦截对象操作,例如读取、写入、删除、has 与 ownKeys,因此 Vue3 能追踪新增键、删除键及更多集合行为。Vue 并不是创建一个最外层 Proxy 后自动获得整个对象图的深层监听,而是在读取嵌套对象时按需要返回相应代理,并处理代理缓存与不同对象类型。
示例与推演
import { reactive, effect } from 'vue'
const state = reactive({ user: { name: 'A' } })
effect(() => console.log(state.user.name))
state.user.name = 'B' // 触发相关依赖
state.user = { name: 'C' } // user 本身也是依赖
读取链路同时经过 user 和 name;直接修改原始对象绕开代理则不应期待同样的触发路径。
易错点
Proxy 是语言能力,track/trigger、调度与 DOM 更新才是框架机制。Map/Set 有专门处理;DOM、Date、第三方实例不应一律强行深代理。
参考回答可直接练习口述
Vue3 对象响应式主要通过 Proxy 拦截读取、设置、删除等操作,读取时追踪当前依赖,写入时触发相关更新,因此新增属性和数组索引修改等比 Vue2 更自然。代理对象与原始对象是不同身份;如果直接修改原始对象,操作绕过代理,就不会经过预期的追踪触发流程。
面试官可能继续问追问与完整解答展开收起
追问
Proxy 能否直接代理基本类型?为什么响应式对象和原始对象不全等?Vue3 官方响应式原理
追问回答
Proxy 的目标必须是对象,不能直接代理字符串、数字等基本值,所以 ref 用一个带 value 访问的对象包装值。reactive(raw) 返回代理而不是 raw 本身,因此两者不全等;应在业务中保持统一使用代理,避免原始与代理混用造成身份判断错误。