关于vue.js:理解Vue中响应式数据

40次阅读

共计 1820 个字符,预计需要花费 5 分钟才能阅读完成。

数组和对象类型当值变动时如何劫持到?

a、对象通过 Object.defineProperty 将属性进行劫持;多重对象通过递归进行实现。

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {
  // 1. 如果对象不可配置则间接退出
  const property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {return}

  // 2. 获取 getter 和 setter
  const getter = property && property.get
  const setter = property && property.set
  
  // 3. 从新定义 set 和 get 办法
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter () {const value = getter ? getter.call(obj) : val
      return value
    },
    set: function reactiveSetter (newVal) {const value = getter ? getter.call(obj) : val
      if (newVal === value || (newVal !== newVal && value !== value)) {return}
      if (getter && !setter) return
      if (setter) {setter.call(obj, newVal)
      } else {val = newVal}
    }
  })
}

这种形式只会监听对象自带的属性,新增的属性监听不到,因而对于新增的属性应用 $set 形式进行数据新增,$set 办法外部会将新增属性定义成响应式数据
b、数组通过重写办法

export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
]
methodsToPatch.forEach(function (method) {
  // cache original method
  const original = arrayProto[method]
  def(arrayMethods, method, function mutator (...args) {const result = original.apply(this, args)
    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)
    return result
  })
})

当操作数组时会调用重写的数组办法,这时就能够监测到数据的变动。因而,如果批改数组索引和长度是不会监听到数组的变动的。

Vue3 中应用 ES6 的 Proxy 代理,Proxy 能够拦挡指标对象的底层操作

let obj = {name: {name: 'lh'}
}
let handler = {get(target,key){ // 这里的命名必须和 Reflect 办法对应
        if(typeof target[key] === 'object' && target[key] !== null){return new Proxy(target[key],handler);
        }
        return Reflect.get(target,key);
    },
    set(target,key,value){let oldValue = target[key];
        if(!oldValue){console.log('新增属性')
        }else if(oldValue !== value){console.log('批改属性')
        }
        return Reflect.set(target,key,value);
    }
}
let proxy = new Proxy(obj,handler);

正文完
 0