Vue 3 中 markRaw 阻止对象转为响应式
FreeGuideOnline
最新
2026-07-07
如果没有 `markRaw`,Vue 会深度代理 `client` 实例,可能破坏其内部 `this` 指向、getter/setter 和事件机制。
#### 在 `ref` 中使用 `markRaw`
`ref` 在内部调用 `reactive` 进行解包包装,所以同样可以使用 `markRaw`:
```js
import { ref, markRaw } from 'vue'
const configRef = ref(markRaw({ version: '1.0', immutable: true }))
// configRef.value 是原始的普通对象,不会变成响应式 Proxy
检查一个对象是否被标记
Vue 没有直接暴露 isRaw 的判断函数,但你可以通过 isReactive 或 isProxy 间接判断:如果确定一个对象在正常逻辑中本应被响应式处理,但调用 isReactive 返回 false,可能就是被 markRaw 标记了。
更准确的方法是检查对象上的 __v_skip 内部属性(这是标记的实际实现机制,不过仅供调试参考,不建议在生产代码中依赖)。
console.log(markedObj.__v_skip) // true (仅在开发环境,不可靠)
注意事项与最佳实践
-
一旦标记,无法撤销
markRaw是永久性的,没有对应的unmark方法。所以只在确信对象不需要响应式时使用。 -
标记只影响对象本身
标记的是对象的引用,而不是其属性。如果你后续向该对象添加新属性,那些属性依然不是响应式的(因为对象整体未被代理),这是符合预期的。 -
不要滥用
大部分情况下,你不需要手动markRaw。Vue 的响应式系统足够聪明,仅在遇到复杂的第三方实例、性能敏感数据时才使用。 -
与
shallowReactive配合
你可以把shallowReactive看作一种“轻度”避免深层响应式的方案;当需要更彻底地“冻住”某个嵌套对象时,再对那个对象单独markRaw。 -
性能优势
对于不需要响应式的超大数组或对象(比如渲染地图的 GeoJSON 数据),markRaw可以显著减少代理创建的耗时和内存占用。
原理浅析
markRaw 内部其实是在对象上定义了一个不可枚举的属性 __v_skip(值为 true)。当 reactive、readonly 等函数尝试对对象进行代理时,会先检查该标记,如果存在则直接返回原始对象,不做任何处理。这是一种侵入性很小且高性能的跳过机制。
// 简化版内部逻辑
function markRaw(obj) {
def(obj, '__v_skip', true)
return obj
}
function reactive(target) {
if (target && target.__v_skip === true) {
return target
}
// ... 正常代理逻辑
}