前端进阶之旅前端进阶之旅
  • 基础篇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 ref 自动解包规则
VuVue响应式原理

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

深层 reactive 对象的 ref 属性会自动解包;数组元素、Map 值和 shallowReactive 根属性不能直接套用这个规则。

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

先确认当前值处于哪个访问位置

  1. 对象属性深层 reactive 的普通属性可读成 ref 内部值
  2. 集合元素数组索引和 Map 值保留 ref,需要显式读取
  3. 浅层边界shallowReactive 不做普通深层对象的解包转换

不要把所有出现点号的访问都理解成对象属性解包;Map.get 的返回值与普通属性读取有不同语义。

核心回答

先记住这个答案

ref 作为普通深层 reactive 对象的属性访问时,Vue 会自动读取它的内部值,并维持对应的响应式联系。给这种属性赋普通值,通常会更新原 ref 的 value;赋入另一个 ref 则会替换原来的引用关系。可是在 reactive 数组的索引元素或 Map 等集合中读取 ref 时,不进行同样的自动解包,需要显式 value。模板又有自己的解包位置规则,应与脚本中的代理行为分别理解。

  • 普通深层对象属性可以自动解包 ref
  • 数组索引、Map 值与浅层对象需要单独判断
  • 赋普通值与赋新 ref 对原连接的影响不同

同一个 ref 放在不同位置,读取方式会不同

例如分页数 ref 放进页面 state 的普通属性中,读取 state.page 可以直接得到数字;把它放进 reactive 数组的第一个元素,读取 pages[0] 仍是 ref 容器。这个差别来自代理对不同位置的处理,不能根据容器都叫 reactive 就推断读取结果相同。

下面的例子把一个 ref 同时用于普通对象、数组、Map 和浅层对象,便于对照读取形式。真实项目不必刻意这样混用;接口越稳定,调用方越容易知道当前拿到的是 ref 还是普通值。通用工具处理未知输入时,也应明确是否接受 ref 并在合适边界规范化。

对照属性与集合元素的读取TypeScript
import { reactive, ref, shallowReactive } from 'vue';

const page = ref(2);
const state = reactive({ page });
const pages = reactive([page]);
const lookup = reactive(new Map([['current', page]]));
const shallow = shallowReactive({ page });

const values = [
  state.page,
  pages[0].value,
  lookup.get('current')!.value,
  shallow.page.value
];
state.page = 5;
const updatedPage = page.value;

Vue 3 中 values 的四项都是 2,而对 state.page 赋普通值后 updatedPage 为 5。数组、Map 和浅层对象处保留显式 value;示例没有控制台输出。

赋普通值与替换 ref 是两种更新

原属性持有一个可写 ref 时,对自动解包后的对象属性写入普通值,可以更新原 ref 的内部值。若向该属性赋入另一个 ref,则会建立与新 ref 的联系,原 ref 不会因为名字相同继续跟随。依赖旧 ref 的其它调用方也不会自动改成持有新 ref。

TypeScript 中 reactive 的解包类型可能让某些直接替换 ref 的赋值不符合当前推导类型,不能因此编造运行时没有替换语义。应选择清楚的数据结构与类型边界,必要时通过明确 API 替换字段,而不是随意断言类型后让调用方猜测字段现在到底是什么。

模板中的便利规则不能推广到全部脚本

在模板中作为顶层绑定暴露的 ref,经常可以直接使用而不写 value;但嵌套在普通对象中的 ref、文本插值最终结果等位置又有具体规则。最可靠的判断方式是分别看模板表达式位置与脚本 API,而不是背一个“Vue 会自动去掉 value”的笼统结论。

shallowReactive 刻意保留浅层行为,不会像普通深层对象那样转换内部 ref。引入这类边界通常是为了控制外部状态集成或转换成本,混在深层对象里可能让访问规则难以预测。设计组合函数返回值时,应统一说明是返回 ref 集合,还是返回可直接访问属性的响应式对象。

回答前,多想一步

容易答错的地方

reactive 数组里的 ref 也能直接加一
数组索引元素不会按普通对象属性规则自动解包。应明确读取和写入元素的 value,避免对 ref 对象本身进行数值运算或错误替换。
给属性换新 ref 后,旧 ref 也会被永久关联
替换会改变这个属性使用的 ref,原来的容器不会自动变成新容器的别名。需要多个位置共享同一个值时,应明确共享哪个稳定 ref,而不是靠不断替换维持联系。
试着用自己的话回答

面试官还会怎么问?

readonly 与 shallowReadonly 的行为完全一样吗?

它们的深浅转换边界不同,不能仅因为都只读就推断内部 ref 解包相同。使用这类包装时,应按具体 API 的深层或浅层约定判断。

Map.get 返回数字还是 ref 怎样确定?

取决于你存进去的值和使用的 API。reactive Map 中存入 ref 时,读取该元素不会自动解包,因此需要 value;存入普通数字则直接得到数字。

组合函数返回多个 ref 可以直接解构吗?

如果返回的是普通对象中的多个 ref,解构得到的仍是那些 ref 容器,联系可以保留。若返回 reactive 对象的原始类型属性,普通解构得到的是当前值,应该分别处理。

从一道题,走向一组知识

把知识连起来

响应式原理

Vue toRef 和 toRefs 怎么选择,和 ref(state.field) 有什么区别?

组合函数和对象解构需要保留字段联系时,可以用 toRef 或 toRefs。

响应式原理

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

理解读取位置之外,还要区分原始对象与代理对象的身份。

参考资料

  • Reactivity Fundamentals: Ref Unwrapping
  • Reactivity API: Core
  • Reactivity API: Advanced

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

本题目录
  1. 先记住这个答案
  2. 同一个 ref 放在不同位置,读取方式会不同
  3. 赋普通值与替换 ref 是两种更新
  4. 模板中的便利规则不能推广到全部脚本
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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