vue 重写数组的七个方法

一、为什么要重写数组方法?

Vue 为了实现响应式数据绑定,需要能够捕获到数据的变化,以便在数据发生改变时自动更新视图。JavaScript 中的数组是引用类型,所以常规的引用跟踪机制不能捕获数组内部的变化。因为Vue的响应式是通过 Object.defineProperty()实现的,这个api没办法监听数组长度的变化,也就没办法监听数组的新增。所以为了更友好的操作数组并触发响应式检测,Vue对改变原数组(数组本身)的方法进行了重写。

Vue通过原型拦截的方式重写了数组的7个方法,首先获取到这个数组的Observer。如果有新的值,就调用observeArray对新的值进行监听,然后调用notify,通知render watcher,执行update。

二、vue重写数组的七个方法分别是哪些?

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

说明:vue只重写了这7个方法,使用其它数组方法不会主动触发试图更新,例如 concat、slice 等,如果需要触发更新,我们可以使用Vue.set() 或 this.$set() 方法手动触发更新。另外,Vue3处理响应数据使用了Proxy,系统会自动捕获这些操作,并在数据变化时触发视图更新,所以不需要重写数组方法。

三、重写数组方法源码

// 获取数组的原型Array.prototype
var arrayProto = Array.prototype

// 新建一个继承于Array的对象
var arrayMethods = Object.create(arrayProto)

// 列出需要重写的数组方法名
var methodsToPatch = [
  "push",
  "pop",
  "shift",
  "unshift",
  "splice",
  "sort",
  "reverse",
]

// 遍历上述数组方法名,依次将上述重写后的数组方法添加到arrayMethods对象上
methodsToPatch.forEach(function (method) {
  // 缓冲原始数组的方法
  var original = arrayProto[method]

  // 利用Object.defineProperty对方法的执行进行改写
  def(arrayMethods, method, function mutator(val) {
    var args = [],
      len = arguments.length;
    while (len--) args[len] = arguments[len]
    // 执行原数组方法
    var result = original.apply(this, args)
    var inserted
    switch (method) {
      case "push":
      case "unshift":
        inserted = args;
        break;
      case "splice":
        inserted = args.slice(2);
        break;
    }
    // 在此处进行通知
    return result
  })
})

// 进行监听
function def(obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  })
}

具体来说,当调用重写的数组方法时,Vue 会执行以下步骤:

1.调用原始的数组方法,例如 push()、pop()、splice() 等。

2.在执行数组方法后,Vue 检测到数组发生了变化。

3.Vue 发出通知,触发视图的重新渲染,确保视图与数据保持同步。

这种重写机制使得开发者在操作数组时无需手动去触发视图更新,Vue 自动为你处理了这部分逻辑。

说明:这些重写仅适用于通过 Vue 实例声明的数组。如果你直接使用原生的数组方法,Vue 将无法捕获到变化,可能导致视图不更新。

你可能感兴趣的:(vue.js,javascript,前端)