Vue3 高频题 · 第 9 题
主问题
问:Vue3 的响应式原理是什么?和 Vue2 的响应式有什么区别?为什么 Vue3 改用了 Proxy?
一、核心回答(面试官满意版)
Vue3 响应式系统基于 Proxy + Reflect + 响应式依赖收集 实现。
Vue2 是用 Object.defineProperty(数据劫持)。
二、Vue2 VS Vue3 响应式系统对比(必答点)
| 对比项 | Vue2(defineProperty) | Vue3(Proxy) |
|---|---|---|
| 基本实现 | 逐个属性劫持 | 整个对象代理 |
| 能否监听新增属性 | ❌ 不行(需 Vue.set) | ✅ 自动感知 |
| 能否监听删除属性 | ❌ 不行 | ✅ 自动感知 |
| 数组下标修改 | ❌ 无法监听 | ✅ 可以监听 |
| 性能 | 大对象性能差 | 更快更可控 |
| API | Vue.set / Vue.delete | 直接赋值即可 |
| 维护成本 | 复杂 | 简洁可扩展 |
三、Vue3 响应式核心原理(逐点解释)
1)通过 Proxy 代理对象
当你访问 / 修改属性时:
get():收集依赖(追踪使用这个属性的 effect)set():触发依赖(更新组件或计算属性)deleteProperty():捕捉属性删除
javascript
const obj = new Proxy(target, {
get(target, key) {},
set(target, key, value) {},
deleteProperty(target, key) {}
})
2)依赖收集(Track)
当模板或 effect 使用某个属性时,Vue 会记录:
"这个 effect 依赖这个属性"
3)触发更新(Trigger)
当属性变化时,Vue 会通知所有依赖它的 effect 重新执行(如组件重新渲染)。
4)使用 Reflect 保证行为一致性
Reflect 提供更标准、更安全的默认行为:
javascript
Reflect.get(target, key, receiver)
Reflect.set(target, key, value, receiver)
这是 Proxy 推荐搭配 Reflect 的原因。
四、Vue3 为什么必须用 Proxy 来替代 defineProperty?(面试官最看重)
你必须讲到 4 个关键理由:
① defineProperty 无法监听新增属性
Vue2 必须:
javascript
Vue.set(obj, 'a', 1)
Vue3: 直接 obj.a = 1 就能监听。
② defineProperty 无法监听删除属性
Vue2 必须:
javascript
Vue.delete(obj, 'a')
Vue3 自然支持:
javascript
delete obj.a // 可监听
③ defineProperty 对数组下标无效
Vue2 对数组:
- 修改 length 无法监听
- arr[2] = xx 不会触发更新
Vue3 Proxy 能完全代理数组:
javascript
arr[1] = 3 // 响应式
④ defineProperty 必须递归遍历对象,性能差
Vue2 初始化时递归所有属性:
- 嵌套越深越卡
- 大对象性能极差
Vue3 Proxy 只代理最外层,访问时再深度递归,性能显著提升。
五、代码示例说明 Vue3 响应式
Vue3 的 reactive 原理示例
javascript
import { reactive, effect } from 'vue'
const state = reactive({ count: 0 })
effect(() => {
console.log('count:', state.count)
})
state.count++ // 自动触发 effect
六、面试官深挖追问(你要能答)
追问 1:Vue3 为什么不支持 IE11?
因为 IE11 不支持 Proxy。 Polyfill 也无法完整模拟 Proxy → 无法实现 Vue3 响应式。
这是 Vue3 UI 框架(如 ElementPlus)不再支持 IE 的根本原因。
追问 2:ref 和 reactive 的响应式实现有区别吗?
有。
reactive
- 使用 Proxy
- 只能作用于 对象/数组
ref
- 使用
RefImpl(内部有 getter/setter) - 可以包基本类型(number/string)
追问 3:为什么 reactive 不适合解构?
因为解构会丢失 Proxy:
javascript
const { count } = reactive(obj) // 非响应式!
解决方法:
javascript
const { count } = toRefs(reactive(obj))
追问 4:Vue3 响应式能否做到"按需追踪依赖"?
能。
Vue3 在 Track 阶段记录"具体的属性依赖", 不会像 Vue2 那样整个对象更新 → 局部更新更高效。
七、killer 问题(高级面试官常用)
❓ "Proxy 在 Vue3 响应式中解决了哪些 Vue2 无法解决的问题?请按重要程度排序。"
最佳回答顺序:
1)无需 Vue.set / Vue.delete 2)数组完整可监听 3)动态属性支持 4)初始化无需递归,性能极大提升 5)可代理整个对象而不是属性 6)更符合 ES 标准(Proxy + Reflect)
这个排序非常加分。
八、最终总结(1 分钟背诵版)
Vue3 使用 Proxy + Reflect 实现响应式,解决了 Vue2 无法监听新增/删除属性、数组下标、性能差等问题。 Proxy 支持全对象代理,性能更好、更语义化、更标准化,因此 Vue3 响应式系统完全重写。 Vue3 的 reactive 基于 Proxy,ref 基于 getter/setter,二者可组合使用。