返回

Vue 数组响应性更新的深入探索:方法、局限和底层实现

前端

Vue.js 数组响应性更新:方法、不支持情况和底层实现

支持响应性更新的方法

Vue.js 提供了多种数组变异方法,可触发响应性更新:

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

这些方法被 Vue.js 内部包裹,当它们被调用时,会触发 notify() 方法,从而更新视图。

不支持的情况

如果使用非变异方法修改数组,例如直接将数组元素重新赋值给新值,则不会触发响应性更新。在这种情况下,需要手动使用 Vue.set() 方法更新数组元素:

// 会触发响应性更新
example1.items.push({ message: 'Foo' });

// 不会触发响应性更新
example1.items[0].message = 'Bar';

// 手动触发响应性更新
Vue.set(example1.items, 0, { message: 'Bar' });

底层实现

Vue.js 通过 Object.defineProperty() 将响应性注入数组。当创建新数组时,Vue.js 会使用 Object.defineProperty() 为数组的 length 和每个索引属性添加 getters 和 setters。这些 getters 和 setters 负责在更改数组时触发 notify() 方法。

具体来说,Vue.js 为每个数组索引属性定义了如下 getter 和 setter:

Object.defineProperty(arr, index, {
  get: function() {
    return this._data[index];
  },
  set: function(val) {
    this._data[index] = val;
    notify();
  }
});

类似地,Vue.js 还为数组的 length 属性定义了 getter 和 setter:

Object.defineProperty(arr, 'length', {
  get: function() {
    return this._data.length;
  },
  set: function(val) {
    this._data.length = val;
    notify();
  }
});

当使用支持的变异方法修改数组时,Vue.js 会直接调用数组索引属性或 length 属性的 setter。这会触发相应的 getter,从而调用 notify() 方法并更新视图。