shallowReadonly 仅对对象第一层属性做只读保护,深层嵌套对象或数组仍可修改;它不递归冻结,适用于需防止顶层替换但保留子状态可变性的场景。

shallowReadonly 是 Vue 3 提供的一个响应式工具函数,它只对对象**第一层属性**做只读保护,内部嵌套的对象或数组仍可被修改。它不递归冻结深层结构,适合在需要“浅层不可赋值但深层可变”的场景中使用,比如防止父级属性被意外替换,同时保留子状态的响应式更新能力。
它和 readonly 的关键区别
不同于 readonly(递归地将整个响应式树转为只读),shallowReadonly 只拦截顶层属性的 set 操作:
- 对
obj.name = 'new'会报错(顶层赋值被禁止) - 对
obj.profile.age = 25不报错(深层属性仍可修改) - 对
obj.list.push(1)也不报错(嵌套数组方法可用)
典型适用场景
常见于组件 props 或组合式 API 中的“受控但非完全冻结”状态:
从零开始编排 SpringBoot+Vue 全栈项目工作流,适用于新建全栈项目或完整脚手架请求,触发后依次调用 product‑spec‑builder(需求调研)等模块。
- 接收父组件传入的配置对象,不允许替换整个 config,但允许内部字段动态更新(如表单字段校验状态)
- 封装一个响应式仓库实例,暴露只读的 state 引用,但保留其内部模块的可变性
- 配合 shallowRef 使用,避免对大型嵌套对象做深度响应式转换带来的性能开销
实际用法示例
在 setup() 中这样使用:
import { shallowReadonly, reactive } from 'vue'
const state = reactive({
user: { name: 'Alice', profile: { age: 30 } },
list: [1, 2]
})
// 仅冻结第一层:user、list 不可被重新赋值
const protectedState = shallowReadonly(state)
// ✅ 允许
protectedState.user.profile.age = 31
protectedState.list.push(3)
// ❌ 报错:Cannot assign to read only property 'user'
// protectedState.user = { name: 'Bob' }
```
注意事项
它不改变原始响应式对象,只是返回一个代理包装;且只对响应式对象(如由 reactive 创建)或普通对象生效:
- 对
ref或shallowRef值需先取.value再包裹 - 对非响应式普通对象也有效,但不会使其变成响应式——只是加一层只读代理
- 类型上,TypeScript 会推导出更精确的只读类型(
DeepReadonly不会,而是ShallowReadonly)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










