• 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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    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()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    Python动态演示旋转矩阵的作用
    学信息系统项目管理师第4版系列29_信息系统治理
    一起Talk Android吧(第三百四十四回: JSON概述)
    【hadoop | hive 搭建】hive的使用配置搭建
    八、Spring Boot - 国际化、登录功能实现 (4)
    1.5 编写自定位ShellCode弹窗
    android源码添加c/c++工程
    java微服务 Dubbo面试题/SpringCloud面试题
    Xilinx FPGA SPIx4 配置速度50M约束语句(Vivado开发环境)
    Tomcat服务器和Web开发介绍
  • 原文地址:https://blog.csdn.net/vgub158/article/details/122690568