• 【vue3源码】十、响应式API中的工具函数


    【vue3源码】十、响应式API中的工具函数

    参考代码版本:vue 3.2.37

    官方文档:https://vuejs.org/

    isRef

    export function isRef(r: any): r is Ref {
      return !!(r && r.__v_isRef === true)
    }
    
    • 1
    • 2
    • 3

    通过对象中是否存在__v_isRef属性并且__v_isRef对应值为true来判断是否为ref

    unref

    export function unref<T>(ref: T | Ref<T>): T {
      return isRef(ref) ? (ref.value as any) : ref
    }
    
    • 1
    • 2
    • 3

    如果是ref则返回ref.value,否则直接返回ref

    toRef

    export function toRef<T extends object, K extends keyof T>(
      object: T,
      key: K,
      defaultValue?: T[K]
    ): ToRef<T[K]> {
      const val = object[key]
      return isRef(val)
        ? val
        : (new ObjectRefImpl(object, key, defaultValue) as any)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    toRef接收三个参数:object待转换的对象、key待转换的keydefaultValue默认值。

    如果object[key]ref,则直接返回object[key]。否则返回一个ObjectRefImpl实例。

    class ObjectRefImpl<T extends object, K extends keyof T> {
      public readonly __v_isRef = true
    
      constructor(
        private readonly _object: T,
        private readonly _key: K,
        private readonly _defaultValue?: T[K]
      ) {}
    
      get value() {
        const val = this._object[this._key]
        return val === undefined ? (this._defaultValue as T[K]) : val
      }
    
      set value(newVal) {
        this._object[this._key] = newVal
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ObjectRefImpl构造器中会分别将objectkeydefaultValue保存至自己的私有属性中,当获取ObjectRefImpl实例的value属性时,会从this._object中获取数据,由于this._object和原来的object内存地址是一致的,所以这和直接使用object获取key获取数据没有区别,只不过经过toRef转换之后,可以和ref那样,通过value属性进行取值、设值。

    toRefs

    export function toRefs<T extends object>(object: T): ToRefs<T> {
      if (__DEV__ && !isProxy(object)) {
        console.warn(`toRefs() expects a reactive object but received a plain one.`)
      }
      const ret: any = isArray(object) ? new Array(object.length) : {}
      for (const key in object) {
        ret[key] = toRef(object, key)
      }
      return ret
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    toRefs中会声明一个新的对象或数组,然后遍历objectkey值,并调用toRef,将结果存入新的对象或数组中,最后返回这个新的对象或数组。

    isReactive

    export function isReactive(value: unknown): boolean {
      if (isReadonly(value)) {
        return isReactive((value as Target)[ReactiveFlags.RAW])
      }
      return !!(value && (value as Target)[ReactiveFlags.IS_REACTIVE])
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果value是只读的,那么就对valueReactiveFlags.RAW属性继续调用isReactive;否则根据valueReactiveFlags.IS_REACTIVE属性判断是否为reactive

    isReadonly

    export function isReadonly(value: unknown): boolean {
      return !!(value && (value as Target)[ReactiveFlags.IS_READONLY])
    }
    
    • 1
    • 2
    • 3

    通过valueReactiveFlags.IS_READONLY属性判断是否只读。

    isProxy

    isProxy是用来判断value是否为reactivereadonly,并不是用来判断valueproxy类型的

    export function isProxy(value: unknown): boolean {
      return isReactive(value) || isReadonly(value)
    }
    
    • 1
    • 2
    • 3

    toRaw

    获取传入对象的原始对象。

    export function toRaw<T>(observed: T): T {
      const raw = observed && (observed as Target)[ReactiveFlags.RAW]
      return raw ? toRaw(raw) : observed
    }
    
    • 1
    • 2
    • 3
    • 4

    observedReactiveFlags.RAW属性可以返回对象的原始对象,但这个原始对象有可能也是可以响应式对象(如readonly(reactive(obj))),所以递归调用toRaw,以获取真正的原始对象。

    markRaw

    将对象标记为永远不能转为reactive对象。

    export function markRaw<T extends object>(
      value: T
    ): T & { [RawSymbol]?: true } {
      def(value, ReactiveFlags.SKIP, true)
      return value
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    通过Object.definePropertyvalueReactiveFlags.SKIP(不会被遍历)属性标记为true。当尝试创建reactive时,会检查该值。

  • 相关阅读:
    【前段基础入门之】=>HTML5 的新增特性!
    leetcode 第454题.四数相加II
    统计学习方法 | 朴素贝叶斯法
    超详细的商业智能BI知识分享,值得收藏
    【Linux】进程概念 —— 孤儿进程与进程优先级
    Vue源码学习(十四):diff算法patch比对
    pdf格式的简历中的照片太小,如何修改图片的大小
    移动WEB开发之流式布局--移动端基础
    保研机试算法训练个人记录笔记(二)
    馒头的1day漏洞巡舰系统
  • 原文地址:https://blog.csdn.net/qq_33635385/article/details/126762999