前端进阶之旅前端进阶之旅
  • 基础篇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 watch props 嵌套属性 getter
VuVue侦听与生命周期

Vue 怎样 watch props 的嵌套属性,直接传属性为什么有时不生效?

先看属性读取后得到的是原始值还是响应式对象,再决定需要观察当前对象内部还是跟随父层替换。

前端进阶之旅 · 一题精讲更新于 2026.09.06
Vue#侦听与生命周期
先看核心答案
理解线索

嵌套属性要回答三件事

  1. 当前类型这次读取的是数字字符串,还是可观察对象
  2. 替换需求父层是否可能提供一个全新的子对象
  3. 深入范围副作用究竟需要 ID、若干字段还是整棵子树

props 的顶层只读并不等于任意嵌套对象都被深冻结,也不能保证传入的普通对象所有内部写入都可追踪。

核心回答

先记住这个答案

props 中的嵌套原始字段应通过 getter 提供给 watch,例如 () => props.user?.id,直接传 props.user.id 得到的只是当前值。若嵌套值本身是响应式对象,直接监听它可以观察那个对象,但不等于会跟随父层把 user 换成新对象。需要同时处理替换与内部变化时,应通过 getter 表达入口,并按需决定深度。watch 只负责观察,不能让子组件获得修改只读 prop 的权限。

  • 原始字段快照不能代替 getter
  • 直接监听子对象与持续读取 prop 入口不是一回事
  • 观察到变化与拥有修改权限是两个不同问题

监听用户 ID,getter 保留了重新读取入口

子组件展示某个用户时,如果副作用只依赖 user.id,可以用 getter 每次从当前 props 读取 ID。父层换了用户对象,或者在可追踪的来源中改变 ID,这个入口都能重新检查当前值。直接调用 watch(props.user.id, callback) 则在注册时就把 ID 读取完了,无法凭那个数字或字符串找回来源。

如果 user 可能暂时为空,可用清楚的空值判断,并定义空 ID 时清理旧数据还是等待加载。可选链只是防止访问不存在的对象,不会自动决定业务重置规则。参数变为无效值时仍保留上个用户的数据,可能让页面产生错误归属,应在同步流程中明确处理。

整个对象的内部变化与父层替换分开测试

watch(props.user, callback) 若拿到响应式对象,可以观察当时的这个对象;但父层后来把 user 指向另一个对象,已有监听并不会自动改成另一条属性入口。使用 () => props.user 可以观察替换,需要内部变化时再添加合适的深度,或直接列出真正相关字段。

嵌套对象来自何处也很重要。父层传入普通对象并在响应式系统之外直接修改字段,并不保证子层深监听凭空收到通知。应保持明确的响应式来源或不可变替换协议,避免把所有漏更新都归咎于 watch 语法,再用 deep 无差别扩大观察范围。

解构与只读约定不能忽略编译边界

在 Vue 3.5 的 script setup 中,defineProps 的某些解构访问有编译转换支持,但这不代表普通 JavaScript 解构自动变成引用。向 watch 传递一个已经求值的原始字段仍需要注意来源形式;通过 getter 包装实际读取,可以让接口更清楚,也更容易跨普通函数边界理解。

监听到变化后,子组件通常通过事件或明确动作请求父层更新,不能直接给只读顶层 prop 赋值。嵌套对象可能因引用共享而允许修改,但这会绕过清楚的单向数据流,除非组件契约明确允许共同编辑,否则应由数据所有者负责变更并处理校验与冲突。

回答前,多想一步

容易答错的地方

任何 props 属性都绝对不能直接传给 watch
若属性本身是有效响应式对象,直接监听可以观察那个对象。真正需要说明的是原始值快照无效,以及直接对象入口未必跟随父层替换,不能把不同情况压成一句绝对规则。
deep 可以让所有普通嵌套对象都自动响应
deep 扩大观察范围,不等于把外部任意写入转换成通知。来源本身的响应式或替换协议仍然必须成立。
试着用自己的话回答

面试官还会怎么问?

只想在用户 ID 改变时重新请求,需要 deep 吗?

通常不需要,直接监听返回 ID 的 getter 更准确。姓名、头像或其它无关字段变化不应仅因对象很大就触发同一请求。

toRef(props, key) 能用于监听吗?

可以作为属性读取入口,但仍保留 props 的只读约束。需要更复杂的嵌套选择时,getter 往往更直接,也能表达空值处理与派生条件。

父组件每次传同内容的新对象,会触发对象 getter 吗?

对象入口的引用变化可能触发,即使业务字段相同。若副作用只关心稳定 ID,可以监听那个原始字段,避免将包装对象身份误当成业务对象变化。

从一道题,走向一组知识

把知识连起来

侦听与生命周期

为什么直接 watch reactive 对象默认深监听,而 watch ref 对象的表现不同?

进一步理解监听当前对象与监听返回对象入口的不同范围。

响应式原理

Vue 3.5 的 <script setup> 中解构 props 为什么还能保持响应式,和普通 reactive 解构有何不同?

props 解构的响应式支持有特定版本与编译场景,不能推广到所有解构。

参考资料

  • Watchers
  • Props
  • Reactivity API: Utilities

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

本题目录
  1. 先记住这个答案
  2. 监听用户 ID,getter 保留了重新读取入口
  3. 整个对象的内部变化与父层替换分开测试
  4. 解构与只读约定不能忽略编译边界
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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