vue响应式系统通过weakmap缓存拦截代理递归、不可枚举内部属性绕过序列化陷阱、markraw/shallowreactive等语义化工具收敛影响范围,以及调度器熔断机制(max_update_count=100)共同防止循环更新。

Vue 响应式系统不靠“禁止循环引用”来规避递归更新,而是通过分层控制、缓存拦截和语义化隔离,在保留合理数据结构的前提下,让循环在关键路径上自动失效。
WeakMap 缓存阻断代理递归
Vue 3 使用 WeakMap 存储原始对象与对应 proxy 的映射。当访问 node.parent = node 这类自引用属性时:
- 首次访问
node.parent,会触发reactive()创建子 proxy; - 再次访问同一对象,
get拦截器查到它已在 WeakMap 中,直接返回已有 proxy; - 不再重复包装,从源头切断响应式代理的无限嵌套。
不可枚举内部属性绕过序列化陷阱
Vue 2 的 __ob__ 和 Vue 3 的 $$state 等标记字段,均设为 enumerable: false:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
-
JSON.stringify()默认只遍历可枚举属性,自动跳过这些元信息; - 即使存在
a.b = a,只要没有其他可枚举的循环链,就能正常序列化; - 但若手动添加可枚举循环(如
user.parent = user),仍会报错——这说明问题不在响应式本身,而在数据建模边界。
主动标记 + 浅层代理收敛影响范围
真正危险的是“不该进响应式的循环”,比如第三方实例或跨 store 引用。Vue 提供轻量语义工具精准收口:
-
markRaw():标记new Map()、API 客户端等,彻底跳过响应式处理; -
shallowReactive():仅代理第一层,适合树形结构、动态表单容器等深层不变场景; -
toRaw():在computed或watch中临时解包,防止 proxy 嵌套加深; - Pinia 推荐用
store.$state或$rawState获取非响应式快照,而非直接JSON.stringify(store)。
调度器内置熔断机制防无限更新
开发环境下,Vue 的调度器会对单次更新循环中的副作用执行次数设限:
- 定义
MAX_UPDATE_COUNT = 100; - 若某 watcher 在一次队列刷新中被触发超 100 次,立即抛警告并中断;
- 典型触发场景:计算属性互相修改(
a依赖b,b又改a)、watch中同步改自身依赖项。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










