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 的判断函数,但你可以通过 isReactiveisProxy 间接判断:如果确定一个对象在正常逻辑中本应被响应式处理,但调用 isReactive 返回 false,可能就是被 markRaw 标记了。

更准确的方法是检查对象上的 __v_skip 内部属性(这是标记的实际实现机制,不过仅供调试参考,不建议在生产代码中依赖)。

console.log(markedObj.__v_skip) // true (仅在开发环境,不可靠)

注意事项与最佳实践

  1. 一旦标记,无法撤销
    markRaw 是永久性的,没有对应的 unmark 方法。所以只在确信对象不需要响应式时使用。

  2. 标记只影响对象本身
    标记的是对象的引用,而不是其属性。如果你后续向该对象添加新属性,那些属性依然不是响应式的(因为对象整体未被代理),这是符合预期的。

  3. 不要滥用
    大部分情况下,你不需要手动 markRaw。Vue 的响应式系统足够聪明,仅在遇到复杂的第三方实例、性能敏感数据时才使用。

  4. shallowReactive 配合
    你可以把 shallowReactive 看作一种“轻度”避免深层响应式的方案;当需要更彻底地“冻住”某个嵌套对象时,再对那个对象单独 markRaw

  5. 性能优势
    对于不需要响应式的超大数组或对象(比如渲染地图的 GeoJSON 数据),markRaw 可以显著减少代理创建的耗时和内存占用。

原理浅析

markRaw 内部其实是在对象上定义了一个不可枚举的属性 __v_skip(值为 true)。当 reactivereadonly 等函数尝试对对象进行代理时,会先检查该标记,如果存在则直接返回原始对象,不做任何处理。这是一种侵入性很小且高性能的跳过机制。

// 简化版内部逻辑
function markRaw(obj) {
  def(obj, '__v_skip', true)
  return obj
}

function reactive(target) {
  if (target && target.__v_skip === true) {
    return target
  }
  // ... 正常代理逻辑
}