vue[源码]之数组处理与拦截变异

先看下拦截数组变异处理的源码:

const arrayProto = Array.prototype //缓存 Array.prototype
// 实现 arrayMethods.__proto__ === Array.prototype  //(拷贝了数组原型下的方法)
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [ 
     'push',   //定义了数组所有的变异方法
     'pop',  
     'shift',  
     'unshift',  
     'splice',  
      'sort',  
      'reverse'
]
/** * Intercept mutating methods and emit events */
methodsToPatch.forEach(function (method) {  //遍历数组
      // 缓存了数组原本的变异方法
      const original = arrayProto[method]  
//使用 def 函数在 arrayMethods 对象上定义与数组变异方法同名的函数,从而做到拦截的目的
 def(arrayMethods, method, function mutator (...args) {
//上定义与数组变异方法同名的函数,在函数体内优先调用了缓存下来的数组变异方法
const result = original.apply(this, args)    
//定义了 ob 常量,它是 this.__ob__ 的引用
       const ob = this.__ob__    
       let inserted    //定义变量
//数组方法对数组的操作
       switch (method) {
         case 'push':      
         case 'unshift':        
         inserted = args        
         break
         case 'splice':
         inserted = args.slice(2)
         break    
} 
//进行观测,达到数组响应式
  if (inserted) ob.observeArray(inserted)    
  // notify change    
  ob.dep.notify()    
  return result   //导出arrayMethods对象 
  })
})复制代码

这段源码主要是对数组变异的拦截处理,定义了一个数组储存了数组变异的方法,遍历得到每一个变异方法。添加到数组原型下面 主要是为了防止在某些浏览器没有__proto__的情况下兼容。

可以看下数组变异拦截方法(
Observer类的 constructor 函数

const arrayKeys = Object.getOwnPropertyNames(arrayMethods)//获取属性名称(要拦截的数组变异方法名字)复制代码

constructor (value: any) {
  this.value = value
  this.dep = new Dep()
  this.vmCount = 0
  def(value, '__ob__', this) //为其定义一个__ob__
  if (Array.isArray(value)) {//判断是否为数组
    if (hasProto) {//检测是否可用__proto__属性        protoAugment(value, arrayMethods)      } else {        copyAugment(value, arrayMethods, arrayKeys)      }
//触发依赖(观察者)观测      this.observeArray(value)
  } else {
    this.walk(value)
  }
}复制代码

protoAugment方法(__proto__)可用情况下复制代码

function protoAugment (target, src: Object) {  /* eslint-disable no-proto */  target.__proto__ = src   /* eslint-enable no-proto */}
//设置数组实例的 __proto__ 属性,让其指向一个代理原型,从而做到拦截复制代码

copyAugment方法(__proto__)不可用情况下
复制代码

function copyAugment (target: Object, src: Object, keys: Array) {  for (let i = 0, l = keys.length; i < l; i++) {    const key = keys[i]    def(target, key, src[key])  }}
//copyAugment 函数的第三个参数 keys 就是定义在 arrayMethods 对象上的所有函数的键,即所有要拦截的数组变异方法的名称。这样通过 for 循环对其进行遍历,并使用 def 函数在数组实例上定义与数组变异方法同名的且不可枚举的函数,这样就实现了拦截操作。(主要为不支持__proto__)做兼容复制代码


转载于:https://juejin.im/post/5ca77792f265da307352dcbd

你可能感兴趣的:(vue[源码]之数组处理与拦截变异)