理解Vue中响应式数据

Posted 前端茅台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解Vue中响应式数据相关的知识,希望对你有一定的参考价值。

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

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);

以上是关于理解Vue中响应式数据的主要内容,如果未能解决你的问题,请参考以下文章

深入理解Vue数据响应式

理解Vue中响应式数据

【手把手教你搓Vue响应式原理】(一)初识Vue响应式

面试题面试官:请你说说对Vue响应式数据的理解

理解响应式编程

深入理解Vue响应式原理