vue2源码-- Vue.set和Vue.delete

Posted 在厕所喝茶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue2源码-- Vue.set和Vue.delete相关的知识,希望对你有一定的参考价值。

目录

Vue.set

作用

给对象或者数组添加一个新的属性。如果对象或者数组是一个响应式数据,那么,新添加的属性也将会变成响应式数据,并且触发视图更新。

原理分析

1、如果target对象为原始类型或者undefinednull,则警告报错

2、如果是数组,并且下标索引是有效的合法值,就会取原数组的长度和传入的下标索引值的最大值作为数组的长度,然后调用splice方法添加数据,因为splice方法被重写了,会把元素自动转化为响应式,并通知更新。返回val

3、如果是对象,并且key值已经在目标对象上面了,直接赋值即可,并返回

4、如果key值不在目标对象上面,先判断目标对象是否为 vue 实例或者 vue 实例的根数据独享,是,则报错,退出程序;然后在判断目标对象上面的__ob__属性是否存在,不存在,说明目标对象并不是一个响应式数据,直接赋值,并退出程序。最后通过调用defineReactive函数添加新属性,并转化为响应式数据,通知更新,退出程序

注意:为什么数组不需要判断__ob__属性是否存在?因为如果是数组是一个响应式数据,那么,调用splice方法是重写过后的,如果不是响应式数据,那么,splice方法是原生的数组方法

源码

源码位于src/core/observer/index.js,第208

export function set (target: Array<any> | Object, key: any, val: any): any 
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) 
    // target为原始类型或者undefined、null,报错
    warn(`Cannot set reactive property on undefined, null, or primitive value: $target`)
  
  // isValidArrayIndex(key)判断索引是否为有效值
  if (Array.isArray(target) && isValidArrayIndex(key)) 
    // 数组的情况

    // 对比2个索引的,取最大的索引作为数组的长度
    target.length = Math.max(target.length, key)
    // 使用splice方法添加数据,因为splice方法被重写了,会把元素自动转化为响应式
    target.splice(key, 1, val)
    return val
  
  // 不是数组就当做对象处理
  if (key in target && !(key in Object.prototype)) 
    // 如果key已经在target上了,直接赋值即可
    target[key] = val
    return val
  
  const ob = target.__ob__
  if (target._isVue || (ob && ob.vmCount)) 
    // 如果target是vue实例或者vue实例的根数据独享,则报错,退出程序
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid adding reactive properties to a Vue instance or its root $data ' +
      'at runtime - declare it upfront in the data option.'
    )
    return val
  
  if (!ob) 
    // ob不存在,说明target不是一个响应式数据
    // 直接赋值即可
    target[key] = val
    return val
  
  // 调用defineReactive方法添加新属性,并转化为响应式数据
  defineReactive(ob.value, key, val)
  // 通知更新
  ob.dep.notify()
  return val

Vue.delete

作用

删除对象或者数组中的属性。如果对象或者数组是一个响应式的数据,会触发视图的更新

原理分析

1、如果target对象为原始类型或者undefinednull,则警告报错

2、如果目标对象是数组,并且下标索引值为有效的,则调用splice方法进行删除

3、如果目标对象是 vue 实例或者是 vue 实例的根数据,则退出,并报错提示

4、如果 key 本来就不存在与目标对象中,则退出函数,什么都不用干

5、使用delete关键字删除属性值,

6、通知更新

源码

源码位于src/core/observer/index.js,第256

export function del (target: Array<any> | Object, key: any) 
  if (process.env.NODE_ENV !== 'production' &&
    (isUndef(target) || isPrimitive(target))
  ) 
    // target不存在或者是原始值的情况下,报错
    warn(`Cannot delete reactive property on undefined, null, or primitive value: $target`)
  
  if (Array.isArray(target) && isValidArrayIndex(key)) 
    // 有效key则使用splice进行删除
    target.splice(key, 1)
    return
  
  const ob = target.__ob__
  if (target._isVue || (ob && ob.vmCount)) 
    // 不能是vue实例或者是vue实例的根数据
    process.env.NODE_ENV !== 'production' && warn(
      'Avoid deleting properties on a Vue instance or its root $data ' +
      '- just set it to null.'
    )
    return
  
  if (!hasOwn(target, key)) 
    // 本来就不存在于target对象中的,就不用删除
    return
  
  // 删除属性值
  delete target[key]
  if (!ob) 
    return
  
  // 如果是一个响应式的情况下,通知更新
  ob.dep.notify()

以上是关于vue2源码-- Vue.set和Vue.delete的主要内容,如果未能解决你的问题,请参考以下文章

vue2源码-- Vue.set和Vue.delete

vue2.0 vue.set()

Vue2基础

vue2.0 实现click点击当前li,动态切换class

从vue源码看Vue.set()和this.$set()

vue项目重构技术要点和总结