toRaw用于将响应式对象还原为原始普通对象,避免Proxy干扰;适用于第三方库传参、JSON序列化、深度比较等场景,但不递归处理嵌套对象,修改原始对象不触发视图更新。

toRaw 是 Vue 3 响应式系统中一个用于“脱敏”的工具函数,它的作用很直接:把被 reactive、ref 或 shallowRef 包裹的响应式对象,还原成它最原始的普通 JavaScript 对象(或原始值),从而绕过 Proxy 代理层,避免触发依赖收集或响应式更新。
什么时候必须用 toRaw?
多数情况下你不需要主动调用 toRaw,但在以下场景它就不可替代:
- 向非 Vue 环境传参(比如第三方库、Canvas API、JSON 序列化、localStorage 存储)时,需要确保传入的是纯对象,而非 Proxy 实例;
- 做深度相等比较(
JSON.stringify或lodash.isEqual)时,Proxy 对象可能引发意外行为或报错; - 在某些底层操作中(如手动 clone、遍历内部属性、访问
constructor或原型方法)发现响应式对象表现异常,怀疑是 Proxy 干扰; - 调试时想确认某个值是否真的被响应式包裹,可对比
toRaw(obj) === obj的结果(为false表示是响应式包装)。
怎么正确调用 toRaw?
toRaw 接收一个参数,返回其原始值。它对非响应式值原样返回,安全无副作用:
import { reactive, toRaw } from 'vue'
const state = reactive({ count: 1, name: 'Alice' })
console.log(toRaw(state)) // { count: 1, name: 'Alice' }
console.log(toRaw(state) === state) // false(说明被代理了)
// 对 ref 也有效
import { ref } from 'vue'
const numRef = ref(42)
console.log(toRaw(numRef)) // 42(注意:不是 { value: 42 })
console.log(toRaw(numRef).value) // ❌ 报错!toRaw(ref) 返回的是原始值,不是 ref 对象
⚠️ 注意:toRaw 不会解构 ref 的 .value 层,而是直接返回 ref 所包装的原始值(如数字、字符串、对象等)。所以别对 toRaw(ref) 再取 .value。
常见误区和避坑点
- 不能用 toRaw “解除响应式”并继续在模板里用:一旦转成普通对象,它就彻底脱离响应式系统,后续修改不会触发视图更新;
-
toRaw 不递归处理嵌套对象:如果响应式对象里有另一个
reactive子对象,toRaw只解开最外层,子对象仍是 Proxy —— 如需完全“扁平化”,得手动递归或配合structuredClone(现代环境); -
不要在模板中调用 toRaw:模板中响应式依赖靠 Proxy 拦截,
toRaw会破坏追踪链,且每次渲染都执行也不必要; -
服务端渲染(SSR)中慎用:Node.js 环境下部分 Proxy 行为与浏览器不同,
toRaw虽仍可用,但要确认目标对象确实被响应式包装过(比如 SSR 中可能压根没触发 reactive)。
替代方案:什么情况下其实不用 toRaw?
很多开发者一遇到“想拿普通对象”就本能想 toRaw,但其实更自然的做法可能是:
- 用
JSON.parse(JSON.stringify(obj))快速深克隆(适合纯数据,不保留函数、undefined、Date 等); - 用
structuredClone(obj)(现代浏览器/Node.js 17+)做真正意义上的深拷贝,保留大多数类型; - 设计时把“原始数据源”单独保存一份(比如
const rawUser = {...}),响应式版本仅用于 UI 层; - 对 ref 使用
unref()(自动解包 ref 或返回原值)比toRaw更语义清晰,尤其在组合式函数中处理泛型输入时。
toRaw 是个精准的手术刀,不是万能转换器。理解它存在的意义——绕过响应式拦截、获取原始引用——才能用得稳、用得少、用得对。










