这道题考察的是 Vue 2 的响应式原理。正确答案是:
✅ 正确答案:A 和 C
A. this.items[index] = newValue ❌ 不是响应式的
C. this.obj.newProperty = 'value' ❌ 不是响应式的
📋 详细解析
A. this.items[index] = newValue ❌
原因:Vue 2 无法检测到通过数组索引直接设置值的变化。
Vue 2 使用 Object.defineProperty 来劫持数组的方法,但无法劫持数组索引操作。
// 错误做法 - 不是响应式的
this.items[0] = 'new value';
// 正确做法 - 使用以下方式之一:
this.$set(this.items, 0, 'new value');
// 或
Vue.set(this.items, 0, 'new value');
// 或
this.items.splice(0, 1, 'new value');
C. this.obj.newProperty = 'value' ❌
原因:Vue 2 无法检测到对象新属性的添加。
由于 Vue 2 在初始化时对已有属性进行响应式处理,新增的属性没有 getter/setter。
// 错误做法 - 不是响应式的
this.obj.newProperty = 'value';
// 正确做法:
this.$set(this.obj, 'newProperty', 'value');
// 或
Vue.set(this.obj, 'newProperty', 'value');
// 或使用 Object.assign(但要注意引用)
this.obj = Object.assign({}, this.obj, { newProperty: 'value' });
✅ 响应式的操作
B. this.items.push(newItem) ✅
原因:Vue 2 重写了数组的变异方法(push、pop、shift、unshift、splice、sort、reverse),这些方法能够触发视图更新。
// 正确做法 - 是响应式的
this.items.push(newItem);
this.items.pop();
this.items.splice(0, 1);
D. this.$set(this.obj, 'newProperty', 'value') ✅
原因:$set 是 Vue 提供的专门方法,用于向响应式对象添加新属性并确保它是响应式的。
// 正确做法 - 是响应式的
this.$set(this.obj, 'newProperty', 'value');
// 等价于
Vue.set(this.obj, 'newProperty', 'value');
🎯 Vue 2 响应式原理要点
数组的响应式限制
Vue 2 无法检测以下数组变动:
- 通过索引直接设置项:
items[index] = newValue - 修改数组长度:
items.length = newLength
对象的响应式限制
Vue 2 无法检测以下对象变动:
- 添加新属性:
obj.newProperty = value - 删除属性:
delete obj.property
解决方案
- 使用
Vue.set()或this.$set() - 使用数组的变异方法
- 对于对象,使用新对象替换旧对象
🔄 Vue 2 vs Vue 3
注意:以上限制主要针对 Vue 2。Vue 3 使用 Proxy 实现了更好的响应式系统,解决了这些问题:
// 在 Vue 3 中,以下操作都是响应式的:
this.items[index] = newValue; // ✅
this.obj.newProperty = 'value'; // ✅
但在 Vue 2 中,A 和 C 确实不是响应式的,因此这道题的正确答案是 A 和 C。
📝 总结
| 操作 | Vue 2 响应式 | 原因 | 解决方案 |
|---|---|---|---|
this.items[index] = newValue |
❌ 否 | 无法检测索引操作 | 使用 $set() 或 splice()
|
this.items.push(newItem) |
✅ 是 | 重写的变异方法 | - |
this.obj.newProperty = 'value' |
❌ 否 | 无法检测新属性 | 使用 $set()
|
this.$set(this.obj, 'newProperty', 'value') |
✅ 是 | Vue 提供的响应式方法 | - |
正确答案:A 和 C