前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Vue reactive 原始对象和代理身份
VuVue响应式原理

Vue reactive 多次代理同一对象会返回同一个值吗,为什么不等于原对象?

普通可代理对象在同一套 reactive 转换中会复用代理,但代理与原始对象仍然是不同身份。

前端进阶之旅 · 一题精讲更新于 2026.09.06
Vue#响应式原理
先看核心答案读代码示例
理解线索

三个身份比较分别在问什么

  1. 原始与代理代理包装访问行为,本身不等于被包装对象
  2. 重复转换同一原始对象对应的已有代理会被复用
  3. 相似数据两个字段一样的新对象仍然有不同身份

本题讨论普通可代理对象;被标记跳过代理、不可扩展对象和特殊内置类型需要按 API 边界分别判断。

核心回答

先记住这个答案

对同一个普通原始对象反复调用 reactive,会得到同一个响应式代理;再次把这个 reactive 代理传给 reactive,也会返回它自身。代理与原始对象不严格相等,因为它们是不同对象,访问代理才会经过响应式处理。这个结论不意味着字段相同的两个对象会合并,也不能随意推广到不同库副本或 readonly、shallow 等不同边界。业务选择与去重通常更适合依据稳定 ID。

  • 同一 raw 的普通 reactive 转换可复用代理
  • raw 与 proxy 不严格相等,字段相同也不代表同一对象
  • 持续使用代理访问状态,避免绕过通知入口

同一原始对象与相同内容不是一回事

接口返回一个商品对象后,多个调用方若对同一个对象引用调用 reactive,不需要各自得到互不相认的普通代理。Vue 会复用这类转换的代理身份。可是再次请求得到一个新的 JSON 对象,即使商品 ID 和名称完全一致,也仍是新的 JavaScript 对象,不会因为内容相等自动命中原对象的身份。

下面示例分别比较重复转换、代理再次转换和另一份同内容对象。它只说明身份关系,不把代理缓存当成业务实体缓存。页面若需要跨请求合并同一商品,还应依据业务 ID 和更新规则组织数据,而不是把 reactive 当作按字段去重的数据库。

重复转换和同内容对象分别比较TypeScript
import { reactive } from 'vue';

const raw = { sku: 'book-7', stock: 3 };
const first = reactive(raw);
const again = reactive(raw);
const sameContent = reactive({ sku: 'book-7', stock: 3 });

const checks = {
  sameRaw: first === again,
  proxyAgain: reactive(first) === first,
  equalsRaw: first === raw,
  sameFields: first === sameContent
};

在 Vue 3 环境中,checks 的前两项为 true,后两项为 false。示例没有控制台输出;比较的是引用身份,并没有比较两个商品字段是否相同。

混用 raw 与 proxy 为什么让集合行为难理解

原生 Set 和 Map 使用对象身份作为键的一部分,若某处保存 raw,另一处拿 proxy 查询,不能简单按严格相等期待命中。Vue 的响应式集合有自己的代理处理,但业务代码若混杂原生集合、外部 SDK 与代理对象,仍容易产生难以追踪的身份差异。

可以在边界统一使用代理,或在业务选择、缓存索引中使用稳定的 sku 等 ID。需要拿原始对象交给某个外部库时,应明确这个边界并避免长期同时保留两条随意写入的路径。toRaw 是临时绕过代理的工具,不能把它当成复制数据或解除所有关联的方法。

直接改原对象不会自动经过代理通知

给 raw.stock 赋值修改的仍是底层同一份数据,但这次写入没有经过响应式代理入口,因此不能依赖它触发 Vue 更新。之后某个逻辑如果因为其它原因读取代理,可能又看见已经变化的字段,这种偶然刷新会让界面表现不一致。

嵌套对象访问也可能返回代理,因此外部保留的原始子对象与 state.child 不一定相等。排查时应追踪对象从哪里进入响应式系统、谁持有哪一个引用以及谁执行写入,而不是到处增加深比较。只读、浅层与多个 Vue 副本的转换语义也不宜与普通 reactive 混为一个全局唯一承诺。

回答前,多想一步

容易答错的地方

reactive 会直接把原对象改造成代理对象
返回的代理是另一种访问入口,并不是把所有已有 raw 引用自动替换掉。先前拿到原对象的调用方仍然持有原引用,直接写它不会自动经过代理处理。
toRaw 返回的是独立快照
它返回对应原始对象,并非深克隆。修改它可能改变代理底层数据而绕过通知;需要快照时应明确复制方案以及数据类型边界。
试着用自己的话回答

面试官还会怎么问?

重新赋值给保存 reactive 的变量会更新所有使用者吗?

不会自动替换其它调用方已经持有的旧代理。需要整体替换对象时,可以考虑稳定的 ref 容器,或让数据所有者明确更新同一代理中的字段。

为什么按对象比较删除列表项有时失败?

待删除项和列表中取出的项可能分别是原始对象与代理,或者来自两次请求的不同实例。先确定业务身份,通常使用稳定 ID 更适合表达要删除哪一个实体。

不同内容的对象能得到同一个代理吗?

对同一个原始对象修改字段并不会改变其代理身份;对两个不同对象,则不能因为内容相近期待共用代理。对象身份与当前字段内容是两个独立维度。

从一道题,走向一组知识

把知识连起来

响应式原理

Vue 3 已经有 reactive,为什么还需要 ref?

需要整体替换数据时,ref 提供另一种稳定读取入口。

响应式原理

Vue reactive 中的 ref 什么时候自动解包,数组和 Map 为什么不同?

代理访问还会涉及 ref 自动解包,需要继续看属性与集合元素的区别。

参考资料

  • Reactivity Fundamentals: Proxy vs Original
  • Reactivity API: Core
  • Reactivity API: Advanced

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 同一原始对象与相同内容不是一回事
  3. 混用 raw 与 proxy 为什么让集合行为难理解
  4. 直接改原对象不会自动经过代理通知
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑