Vue底层props只读保护本质是Proxy拦截顶层赋值/删除操作,不冻结原始数据;子组件拿到的是shallowReadonly代理,故props.user.name修改不报错,因Proxy不递归拦截嵌套属性,需父组件用readonly提前封装实现深层防护。

Vue 底层对 props 对象的只读保护,本质是**用 Proxy 拦截属性赋值、删除和重配置操作**,不是冻结原始数据,而是给访问路径加一层“防护网”——子组件拿到的不是原始 reactive 对象,而是一个被包装过的只读代理。
props 本身已是 shallowReadonly 代理
父组件传入的 props,在子组件内部已被 Vue 自动封装为 shallowReadonly 代理。这意味着:
- 顶层属性(如
props.count、props.user)禁止重新赋值或删除:执行props.count = 5或delete props.user会触发开发环境警告 - 但嵌套对象内部(如
props.user.name)不拦截——因为只读仅作用于第一层,这是 JavaScript 引用传递的自然结果,不是漏洞,而是设计取舍 - 该代理仍保持响应式:原始数据变了,props 读出来的值实时更新,视图照常重渲染
为什么深层修改不报错?
当父组件传入 reactive({ user: { name: 'Alice' } }),子组件写 props.user.name = 'Bob' 不报错,是因为:
-
props.user返回的是原始响应式对象的引用,没被 readonly 包裹 - Proxy 拦截的是对
props这个代理对象自身的操作,不递归拦截其属性值上的操作 - 这属于“引用类型可变”的语言特性,Vue 不做覆盖,而是靠协作规范来规避
真正起作用的拦截行为有哪些?
在开发模式下,以下操作会被 Proxy 明确捕获并警告:
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
-
props.xxx = value(顶层属性赋值) -
props.xxx++或props.xxx += 1(本质是先读再写) delete props.xxxObject.defineProperty(props, 'xxx', {...})- 对只读 ref:如
props.countRef.value = 10
生产环境这些操作静默失败,不抛错也不生效。
如何让深层也受保护?
靠父组件主动封装,而不是等子组件处理:
- 传对象前用
readonly(reactive({...}))→ 全层级拦截新增、修改、删除 - 传 ref 前用
readonly(ref(...))→ 拦截.value赋值 - 避免直接传裸 reactive 对象;若必须共享,provide/inject 时也需包装
不复杂但容易忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









