面试题:Vue 2 修改了数组的哪些方法?为什么?

在 Vue 2 中,为了实现对数组的响应式监听,Vue 对数组的某些原生方法进行了重写。这是因为 JavaScript 的限制,Vue 无法直接通过 Object.defineProperty 监听数组的变化。以下是 Vue 2 修改的数组方法及其原因:


1. Vue 2 修改的数组方法

Vue 2 重写了以下数组方法,使其能够触发视图更新:

  • push():向数组末尾添加一个或多个元素。
  • pop():移除数组的最后一个元素。
  • shift():移除数组的第一个元素。
  • unshift():向数组开头添加一个或多个元素。
  • splice():从数组中添加/删除元素。
  • sort():对数组进行排序。
  • reverse():反转数组的顺序。

2. 为什么需要重写这些方法?

(1)JavaScript 的限制

  • Vue 2 使用 Object.defineProperty 实现响应式数据。Object.defineProperty 只能监听对象属性的 读取赋值,无法直接监听数组的变化(如 pushpop 等操作)。
  • 数组的 length 属性也无法通过 Object.defineProperty 监听。

(2)重写方法的实现

Vue 2 通过重写数组的原型方法,在调用这些方法时,除了执行原生操作外,还会触发视图更新。

示例:

const arrayProto = Array.prototype; // 获取数组的原型
const arrayMethods = Object.create(arrayProto); // 创建一个新的对象,继承数组的原型

// 重写数组方法
['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach((method) => {
  const original = arrayProto[method]; // 缓存原生方法
  Object.defineProperty(arrayMethods, method, {
    value: function mutator(...args) {
      const result = original.apply(this, args); // 调用原生方法
      const ob = this.__ob__; // 获取 Observer 实例
      ob.dep.notify(); // 触发依赖更新
      return result;
    },
    enumerable: false,
    writable: true,
    configurable: true,
  });
});

(3)如何替换数组的原型

Vue 2 在将数组转换为响应式数据时,会将数组的原型替换为上述重写后的原型。

function observeArray(arr) {
  arr.__proto__ = arrayMethods; // 替换数组的原型
}

3. Vue 2 中数组的局限性

尽管 Vue 2 重写了数组方法,但仍有一些操作无法触发视图更新:

  • 直接通过索引修改数组元素
  this.items[0] = 'new value'; // 不会触发视图更新
  • 修改数组长度
  this.items.length = 0; // 不会触发视图更新

解决方法:

  • 使用 Vue.setthis.$set 修改数组元素:
  this.$set(this.items, 0, 'new value'); // 触发视图更新
  • 使用 splice 修改数组长度:
  this.items.splice(0); // 触发视图更新

4. Vue 3 的改进

在 Vue 3 中,使用 Proxy 替代了 Object.defineProperty,能够直接监听数组的变化,包括通过索引修改元素和修改数组长度。因此,Vue 3 不再需要重写数组方法。


总结

  • Vue 2 重写的数组方法pushpopshiftunshiftsplicesortreverse
  • 重写的原因Object.defineProperty 无法直接监听数组的变化,重写方法可以触发视图更新。
  • 局限性:直接通过索引修改数组元素或修改数组长度不会触发更新,需要使用 Vue.setsplice
  • Vue 3 的改进:使用 Proxy 直接监听数组变化,无需重写数组方法。

理解 Vue 2 对数组方法的处理,可以帮助你更好地使用 Vue 的响应式系统,并避免常见的陷阱。

THE END
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容