Vue源码的原理-数组的响应式

132 阅读1分钟

Vue源码学习记录

参考于 深入浅出vue.js此书

上文已经讲了数组是通过重写方法来实现响应式的

数组的实现原理:

拦截器实现
const arrayProto = Array.prototype
  const arrayMethods = Object.create(arrayProto)
  ['push','pop','shift','unshift','reverse','sort'].forEach(function(method) {
      const original = arrayProto[method]
      Object.defineProperty(arrayMethods,method,{
        value: function mutator(...args) {
          return original.apply(this,args)
        },
        enumerable: false,
        writable: true,
        configurable: true
      })
  })
收集依赖

和对象一样也是在defineReactive中的get收集

function defineReactive(data,key,val) {
    let childObj = Observer(val) // 将对象递归子属性写法修改
    let dep = new Dep() // 将依赖收集加入
    Object.defineProperty(data,key,{
      enumerable: true,
      configurable: true,
      get:function() {
        dep.depend() // 对象收集依赖
        if(childObj) {
          childObj.dep.depend() // 数组收集依赖
        }
        return val
      },
      set(newVal) { // 在set中触发依赖
        if(val === newVal) {
          return
        }
        val = newVal
        dep.notify()
      }
    })
  }
存依赖
const hasProto = __proto__ in {} // 当前浏览器是否支持__proto__
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
class Observer{
    constructor(value) {
      this.value = value
      this.dep = new Dep() // 为了在拦截器中也可以访问到
      if(Array.isArray(value)) {
        const agument = hasProto? protoAugment: copyAugment
        agument(value,arrayMethods,arrayKeys) //存放数组的依赖
      } else {
        // 对象操作:上篇文章已写
      }
    }
  }
  function protoAugment(target,src,keys) {
      target.__proto__ = src
  }
  function copyAugment(target,src,keys) {
      for(let i=0;i<keys.length;i++) {
        Def(target.keys[i],src[keys[i]])
      }
  }