天天看點

vue3源碼值ref

一、入口函數:

export function ref(value?: unknown) {
  return createRef(value, false)
}
           

二、實際調用方法為

createRef

:

function createRef(rawValue: unknown, shallow: boolean) {
  // 首先進行判斷傳入的 rawValue 是否為 ref
  if (isRef(rawValue)) {
    return rawValue
  }
  // 傳入的 rawValue 是一個非 ref 的值,将他傳入對象 RefImpl 構造為一個 ref 
  return new RefImpl(rawValue, shallow)
}
           

ref 的核心類 RefImpl,ref 方法的核心就是通過它進行執行個體化類:

​ 我們在使用

ref

的時候,會通過

ref.value

擷取值,此處的

value

就是該類中的 get 和 set ,get 和 set 就是通過getter/setter來截取對象成員的通路。

​ 分析一下getter和setter是什麼?

getter:

​ 定義:

get

文法将對象屬性綁定到查詢該屬性時将被調用的函數。

​ 文法:

{get prop() { ... } }

​ 參數: prop: 要綁定到給定函數的屬性名。

​ 描述:有時需要允許通路傳回動态計算值的屬性,或者你可能需要反映内部變量的狀态,而不需要使用顯式方法調用。在 JavaScript 中,可以使用 getter 來實作。

​ 注意:

​ 1、在class中使用時,屬性會被定義在執行個體的原型上

​ 2、當使用

Object.defineProperty()

時,屬性将被定義在執行個體自身上。

​ 簡單了解:在調用一個對象的時候,如果不想調用顯示方法來擷取某個值,可以通過調用 get 來實作。

setter:

定義:當嘗試設定屬性時,**

set

**文法将對象屬性綁定到要調用的函數。

文法:

{set prop(val) { . . . }}

參數:prop: 要綁定到給定函數的屬性名。

​ val: 用于儲存嘗試配置設定給

prop

的值的變量的一個别名。

描述: javascript 中,如果試着改變一個屬性的值,那麼對應的 setter 将被執行。setter 經常和 getter 連用以建立一個僞屬性。不可能在具有真實值的屬性上同時擁有一個 setter 器。

簡單了解:如果想要去改變屬性的值,可以調用 set。

class RefImpl<T> {
  private _value: T
  private _rawValue: T

  public dep?: Dep = undefined
  public readonly __v_isRef = true

  constructor(value: T, public readonly __v_isShallow: boolean) {
    // toRaw 傳回傳入值的原始對象
    // toReactive 判斷是否傳回 reactive 類型
    this._rawValue = __v_isShallow ? value : toRaw(value)
    this._value = __v_isShallow ? value : toReactive(value)
  }

  get value() {
    trackRefValue(this)
    return this._value
  }

  set value(newVal) {
    const useDirectValue =
      this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
    newVal = useDirectValue ? newVal : toRaw(newVal)
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = useDirectValue ? newVal : toReactive(newVal)
      triggerRefValue(this, newVal)
    }
  }
}
           

最後分析一下,第一步中判斷傳入 rawValue 是否為 ref :

function createRef(rawValue: unknown, shallow: boolean) {
  // 首先進行判斷傳入的 rawValue 是否為 ref
  if (isRef(rawValue)) {
    return rawValue
  }
  // 傳入的 rawValue 是一個非 ref 的值,将他傳入對象 RefImpl 構造為一個 ref 
  return new RefImpl(rawValue, shallow)
}
           

在這一步中,核心是調用了 ifRef() 方法進行判斷:

如果是一個 ref 執行個體,那麼它自身就會具有 .__v_isRef 屬性。

export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
  // 判斷傳入的 r 是否具有 __v_isRef 屬性且為true,如果具有此屬性,說明它本身就是一個 ref 的執行個體
  return !!(r && r.__v_isRef === true)
}
           

繼續閱讀