标准答案
- Vue 2 响应式基于 Object.defineProperty,把 data 中已有属性转换成 getter / setter。读取时收集依赖,设置时通知更新。
- Vue 2 的限制是只能劫持已有属性。对象新增属性、删除属性、数组索引赋值和 length 修改等场景不能被完整拦截,所以需要 Vue.set、this.$set 或数组变更方法兜底。
- Vue 3 使用 Proxy 包裹整个对象,能拦截 get、set、deleteProperty、has、ownKeys 等更多操作,对对象新增、删除、数组索引变化的支持更自然。
- Vue 3 的响应式还把核心能力拆到 @vue/reactivity,配合 effect、track、trigger、ref、reactive 等机制组织依赖。
- Proxy 的代价是不能兼容 IE11,且代理对象和原始对象不是同一个引用,解构、toRaw、markRaw、浅响应式等边界需要理解。
题目解析
这题可以按“拦截方式、能覆盖的操作、数组和对象限制、迁移影响”来理解。
Vue 2 的 defineProperty 不是不能做响应式,而是它只能对属性做拦截,无法天然知道属性新增和删除。
Vue 3 改用 Proxy 后,响应式边界更完整,但仍然不是没有坑。比如直接解构 reactive 对象属性会丢失响应式连接。
代码示例
这段代码展示 Vue 2 常见限制,以及 Vue 3 中新增属性可以被代理拦截。
JavaScript
// Vue 2 常见写法
this.$set(this.user, 'age', 18)
this.items.splice(index, 1, nextItem)
// Vue 3 reactive 对新增属性更自然
const user = reactive({ name: 'Alice' })
user.age = 18
delete user.name常见误区
- 只回答 defineProperty 和 Proxy 的 API 名称,不说明它们能拦截哪些变化。
- 认为 Vue 3 响应式没有任何边界。解构、原始对象引用、浅响应式仍然需要注意。
- 认为 Vue 2 数组完全不能响应。通过 push、splice、sort 等被改写的方法,Vue 2 仍然能触发更新。