readonly 是 Vue 3 的响应式工具函数,创建对 reactive 或 ref 的深度只读代理,不拷贝数据、开发时修改报警告、生产时静默失败;它不改变原对象可写性,且与 computed 语义不同,适用于限制消费方修改权限的场景。

readonly 是 Vue 3 提供的一个响应式工具函数,用于创建一个对原始响应式对象(或 ref)的只读代理。它不会拷贝数据,而是返回一个代理对象,任何试图修改它的操作(如赋值、删除属性、添加新属性、调用可变方法等)在开发模式下会发出警告,在生产模式下静默失败。
基本用法:包装 reactive 或 ref
你可以用 readonly 包裹 reactive 创建的对象,或包裹 ref(包括普通 ref 和 shallowRef):
- 对 reactive 对象使用:const state = readonly(reactive({ count: 0 }))
- 对 ref 使用:const countRef = readonly(ref(10))
- 注意:readonly 不改变原对象,原对象仍可写;只读代理仅作用于返回的代理对象本身
只读是深层的(递归的)
readonly 默认会对嵌套对象、数组、Map、Set 等也应用只读代理 —— 即整个响应式结构是深度只读的:
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
- 例如:const obj = readonly(reactive({ user: { name: 'Alice' } })) → obj.user.name = 'Bob' 会触发警告
- 数组方法如 push、pop、splice 同样被禁止
- 但注意:只读代理不阻止对原始对象的修改,所以应避免同时持有可写引用和只读引用并分别操作
与 computed 的区别
readonly 和 computed 都能提供“不可修改”的访问方式,但语义和行为不同:
立即学习“前端免费学习笔记(深入)”;
- computed 是惰性求值 + 缓存的派生值,适合基于响应式源计算新值
- readonly 是直接代理原始响应式数据,无额外计算开销,适用于“限制消费方修改权限”的场景(如 props、子组件接收状态)
- 常见模式:defineProps 返回的 props 在内部就是用 readonly 包装的
注意事项和常见误区
- 只读代理无法解构后保持只读:const { count } = readonly(reactive({ count: 1 })) → count 是普通 number,不再受保护
- 不能对普通对象(非响应式)直接使用 readonly 来获得响应式能力;它只代理已有的响应式结构
- 类型上,TypeScript 会自动推导为 DeepReadonly
,确保类型层面也体现只读性 - 如需部分只读或浅层只读,可用 shallowReadonly 替代

















