一、入口函數:
export function ref(value?: unknown) {
return createRef(value, false)
}
二、實際調用方法為 createRef
:
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)
}