vue2源码学习-Array七种原型方法hack

在Vue2中如果直接通过下标修改数组的值,不会触发视图的更新,只能通过push、pop、shift、unshift、splice、sort和reverse7种方法改变才会触发响应式更新。尤大的解释是直接监听数组的下标会带来性能损耗,所以通过hack的方式覆写这些编译方法。

其实现原理如下,每行代码都进行了注释:

// 源码目录:src/core/array.js

// 获取工具方法def,定义对象的数据描述符
import {
    
     def } from '../util/index'

// 获得Array的原型对象
const arrayProto = Array.prototype
// 继承Array的原型,后面defineProperty修改属性描述符,实现原型法的hack
export const arrayMethods = Object.create(arrayProto)

// hack的7种会修改数组元素的方法
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]

// 通过修改数据描述符,拦截这7种方法,并派发更新
methodsToPatch.forEach(function (method) {
    
    
  // 暂存初始Array的原型方法
  const original = arrayProto[method]
  // 修改数据描述符
  def(arrayMethods, method, function mutator (...args) {
    
    
    // 调用原生方法,存储结果
    const result = original.apply(this, args)
    // 获取当前Vue实例的Observer
    const ob = this.__ob__
    // 保存插入的数据,需要转换成响应式数据
    let inserted
    // push、unshift、splice三种方法会插入,分别取得其对应的插入值
    switch (method) {
    
    
      case 'push':
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    // 将插入的数据也转换成响应式
    if (inserted) ob.observeArray(inserted)
    // 派发更新
    // 每个Observer都管理一个依赖收集器Dep,当触发setter时,就是通过Dep派发更新,让Watcher更新视图。
    ob.dep.notify()
    // 返回执行结果
    return result
  })
})

其中__ob__获取Observer实例,我们查看observer的源码

// 源码目录:src/observer/index.js

// 观察数组
observeArray (items: Array<any>) {
    
    
  for (let i = 0, l = items.length; i < l; i++) {
    
    
    // 使数组元素变为响应式数据
    observe(items[i])
  }
}

猜你喜欢

转载自blog.csdn.net/sinat_36521655/article/details/109188885