readonly 是 vue 3 创建深度只读响应式代理的 api,接收 reactive 对象、ref 或普通对象并返回只读代理;开发时修改触发警告,生产环境静默失败,嵌套属性自动受保护,且不干扰原对象响应性。

readonly 是 Vue 3 提供的响应式 API,用于为响应式对象或普通对象创建一个深度只读的代理。它不改变原始数据,也不影响其响应性,只是加了一层“只读访问控制”——你在开发时误改会收到警告,生产环境则静默忽略。
怎么用 readonly 包装数据
它接收 reactive 对象、ref 或普通对象,返回只读代理:
- 对
reactive对象:直接传入,返回只读代理 - 对
ref:传入 ref 实例本身(不是.value),返回只读 ref - 对普通对象:也能用,但注意它不会自动转为响应式,仅提供只读保护
示例:
使用 `@ainative/vue-sdk` 为 Vue 3 应用添加 AI 聊天功能。适用于以下场景:(1) 安装 `@ainative/vue-sdk`,(2) 在 Vue 组件中使用 `useChat` 组合式函数,(3) 提供……
import { reactive, ref, readonly } from 'vue'<br><br>const state = reactive({ count: 0, user: { name: 'Alice' } })<br>const countRef = ref(100)<br><br>const safeState = readonly(state) // 深度只读代理<br>const safeCount = readonly(countRef) // 只读 ref<br><br>console.log(safeState.count) // ✅ 正常读取<br>safeState.count = 99 // ⚠️ 开发环境警告,无效<br>safeState.user.name = 'Bob' // ⚠️ 嵌套属性同样受保护
什么时候必须在父组件提前包装
最典型场景是父组件向子组件传递状态:
- 子组件接收 props 后,若意外执行
props.data.name = 'xxx'或props.list.push(...),可能污染共享状态 - 正确做法是在父组件中用
readonly()封装好再传,而不是让子组件自己包——props 本身已是只读代理,再包一层无意义且易掩盖问题 - 尤其适用于多个子组件共用同一响应式对象,需防止某一方误改
readonly 和 shallowReadonly 的关键区别
两者都返回只读代理,但保护深度不同:
-
readonly是深层只读:所有嵌套对象、数组项、ref 解包后的值都不可改 -
shallowReadonly只冻结第一层属性:比如obj.info.age = 25仍可成功,适合性能敏感或只需顶层防护的场景
如何确认一个对象是否只读
用 isReadonly() 判断:
-
isReadonly(safeState)→true -
isReadonly(state)→false(原始 reactive 对象不是只读代理) - 它检查的是对象内部的
__v_isReadonly标记,不是靠 try-catch 或属性枚举
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









