看源碼時候做的筆記-----------
1.ref是什么?
from:vue-next/packages/reactivity/src/ref.ts
示例:
import { ref, ref } from 'vue';
let a: Ref<String> = ref('hello world');
let b: Ref<Object> = ref({name: 'hello world'});
console.log(b)
生成的變量:

首先變量a的類型是 Ref<String>,這個類型 Ref的定義如下,包含了 value,_shallow,[RefSymbol]。我們從上圖看,ref變量里面還有 __v_isRef、_rawValue、_value、_shallow
declare const RefSymbol: unique symbol export interface Ref<T = any> { value: T /** * Type differentiator only. * We need this to be in public d.ts but don't want it to show up in IDE * autocomplete, so we use a private Symbol instead. */ [RefSymbol]: true /** * @internal */ _shallow?: boolean }
再看看 ref 的實現:
(ts的函數重載: https://jkchao.github.io/typescript-book-chinese/typings/functions.html#%E9%87%8D%E8%BD%BD
export function ref<T extends object>(value: T): ToRef<T> export function ref<T>(value: T): Ref<UnwrapRef<T>> export function ref<T = any>(): Ref<T | undefined> export function ref(value?: unknown) { return createRef(value) } function createRef(rawValue: unknown, shallow = false) { if (isRef(rawValue)) { return rawValue }
// RefImpl 實例會初始化 __v_isRef、_rawValue、_value、_shallow
// __v_isRef 用在isRef func中判斷,當前變量是不是ref
return new RefImpl(rawValue, shallow)
}
RefImpl在構造ref的時候 ,會判斷用戶傳入的_rawValue是不是object,不是object就直接賦值給_value, 是object就 convert(_rawValue)
const convert = <T extends unknown>(val: T): T =>
isObject(val) ? reactive(val) : val
可以看出來,最后將object類型的變量,構造為reactive的proxy。
2.reactive是什么?
from:vue-next/packages/reactivity/src/reactive.ts
響應性基礎API:https://www.vue3js.cn/docs/zh/api/basic-reactivity.html#reactive
2.1.reactiveMap 和 readonlyMap 為什么是 weakMap,WeakMap 和 Map有什么區別?
Map 是由 key 數組和 value 數組構成,遍歷時,先遍歷 key, 找到 index , 然后再從 value 數組取值。兩個很大的缺點:
a) 賦值和搜索操作都是 O(n) 的時間復雜度( n 是鍵值對的個數),因為這兩個操作都需要遍歷全部整個數組來進行匹配。
b) 是可能會導致內存泄漏,因為數組會一直引用着每個鍵和值。這種引用使得垃圾回收算法不能回收處理他們,即使沒有其他任何引用存在了。
WeakMap 對象是一組鍵/值對的集合,其中的鍵是弱引用的,因為是弱引用,所以key不可被枚舉,如果key 是可枚舉的話,其列表將會受垃圾回收機制的影響,從而得到不確定的結果。其鍵必須是對象,而值可以是任意的。
a) WeakMap 持有的是每個鍵對象的“弱引用”,而弱引用的對象,垃圾回收機制不考慮對該對象的引用,這意味着在沒有其他引用存在時垃圾回收能正確進行。
原生 WeakMap 的結構是特殊且有效的,其用於映射的 key 只有在其沒有被回收時才是有效的。
effec.ts 中,Dep是個set,KeyToDepMap 是個 Map,targetMap 也是個WeakMap。
2.2.Reflect 和 Object 有什么區別?
2.3 怎么定義reactive數據?
可以創建reactive、shallowReactive、readonly、shallowReadonly四種不同的reactive數據類型,具體解釋見:https://www.vue3js.cn/docs/zh/api/basic-reactivity.html#markraw
每種reactive類型對應不同的createHandler,分別是mutableHandlers、shallowReactiveHandlers、readonlyHandlers、shallowReadonlyHandlers,
創建過程中,需要檢測teaget是否是readonly、是否已經是reactive、是否已經被標記為raw類型、是否是基礎類型不可擴展、是否已經存在於map中,並做相應處理。
未創建並且滿足創建條件的,將target轉換為proxy:

baseHandlers 和 collectionHandlers,負責給proxy傳入不同的劫持handler。
2.4 怎么創建reactive數據類型?
那 collectionHandlers(適用於Map/WeakMap/Set/WeakSet類型的target)和 baseHandlers (適用於Object和Array類型的target)有什么區別?
2.4.1:baseHandlers:vue-next/packages/reactivity/src/baseHandlers.ts
其實baseHandler主要是為proxy提供了handler:
reactiveVar = new Proxy( {}, { get, set, has, deleteProperty, ownKeys } ) = new Proxy({},handler)

在baseHandlers中,createGetter 負責創建get/shallowGet/readonlyGet/shallowReadonlyGet,區分在key是symbol、readonly、shallow、ref等情況下key的返回值,根絕情況確認是否要track追蹤收集依賴。
createGetter(isReadonly = false, shallow = false) {
// 處理 __v_isReactive、__v_isReadonly、__v_raw 情況
// 處理 數組取值
// 處理 key 是symbol的情況
// track
// 處理shallow和ref的情況
// 處理 res(Reflect.get(target, key, receiver))是object的情況,遞歸處理nested varabiles
}
createSetter 負責創建 set/shallowSet,(readonly不需要set)
function set( target: object, key: string | symbol, value: unknown, receiver: object): boolean { // 處理 非shallow非數組且isRef的情況,直接賦值 // 處理 數組復制的情況 Reflect.set(target, key, value, receiver), trigger }
2.4.2:collectionHandlers:vue-next/packages/reactivity/src/collectionHandlers.ts
因為 collectionHandler 處理的對象類型的特殊性,key是object,所以 collectionHandlers 給proxy提供的handler類型很多。

總歸來說,就是將各種數據類型分為了三類,分別處理,生成proxy,將數據置為reactive

最后,可以實踐一下,看看reactive的產物,有什么區別?
const wm1 = new WeakMap(); const o1 = {}, o2 = function(){}, o3 = window; wm1.set(o1, 37); wm1.set(o2, "azerty"); const ws = new WeakSet(); const foo = {}; const bar = {}; ws.add(foo); ws.add(bar); const testCOMMONobject = reactive({ a: 1, b: 'test', }); console.log(testCOMMONobject); const testCOMMONarr = reactive(['測試數組', '測試數組1', '測試數組2']) console.log(testCOMMONarr) const testCOLLECTIONwm = reactive(wm1); console.log(testCOLLECTIONwm) const testCOLLECTIONws = reactive(ws); console.log(testCOLLECTIONws) console.log(readonly(testCOMMONobject)); console.log(markRaw(testCOMMONarr)) // __v_skip: true
reactive的原理就是生成proxy劫持,在setter時候trigger,在trigger中收集目標並觸發effects,最終觸發patch。
3.trigger和track是怎么生效的?
import { track, trigger } from './effect';
from: vue-next/packages/reactivity/src/effect.ts
3.1.哪些操作operations會觸發track和trigger?

當對一個對象進行get、has、iterate的時候,會觸發該對象的track,收集依賴到targetMap。對對象進行set、add、delete、clear時會觸發trigger,使用target中的deps觸發依賴追蹤。
3.2.怎么收集保存對象的依賴信息?
我們來看源碼,源碼先聲明了一個targetMap來保存對象的依賴信息:
(不得不說,vue3 也是一本 typescript 高級教程😂
// The main WeakMap that stores {target -> key -> dep} connections. // Conceptually, it's easier to think of a dependency as a Dep class // which maintains a Set of subscribers, but we simply store them as // raw Sets to reduce memory overhead. type Dep = Set<ReactiveEffect> type KeyToDepMap = Map<any, Dep> const targetMap = new WeakMap<any, KeyToDepMap>() export interface ReactiveEffect<T = any> {
// 限制這個接口的實現必須是一個返回值為T(泛型)的函數,https://forum.vuejs.org/t/vue3-0-ts-t/81276
(): T
_isEffect: true id: number active: boolean raw: () => T deps: Array<Dep> options: ReactiveEffectOptions allowRecurse: boolean }
3.3.track
track(obj, TrackOpTypes.GET,'a');
運行示例,就可以看到target的數據結構:
const obj = { a: '1', } const targetMap = new WeakMap(); const depsMap = new Map() targetMap.set(obj, depsMap); let dep = depsMap.get('a') if (!dep) { depsMap.set('a', (dep = new Set())) } let effect = {}; effect.id = 2; effect.allowRecurse = true; effect._isEffect = true; effect.active = true; effect.raw = () => {}; effect.deps = []; effect.options = {}; dep.add(effect); effect.deps.push(dep); console.log(targetMap)
我們通過一個實例:
const obj = { a: '1', } track(obj, TrackOpTypes.GET, 'a');
看看track的運行過程,看看track是如何收集obj.a的依賴的:
export function track(target: object, type: TrackOpTypes, key: unknown) { if (!shouldTrack || activeEffect === undefined) { return } // 查詢 targetMap 中是否保存有 obj 的依賴,obj是否被追蹤 let depsMap = targetMap.get(target) // 如果 depsMap 不存在,targetMap.set(obj, new Map()),添加obj的依賴追蹤 if (!depsMap) { targetMap.set(target, (depsMap = new Map())) } // 查詢targetMap的 key -> obj 中是否有 'a'的依賴追蹤,如果沒有添加 let dep = depsMap.get(key) if (!dep) { // depsMap.set('a', new Set()) depsMap.set(key, (dep = new Set())) } // 如果沒有 activeEffect,新增 if (!dep.has(activeEffect)) { dep.add(activeEffect) activeEffect.deps.push(dep) if (__DEV__ && activeEffect.options.onTrack) { activeEffect.options.onTrack({ effect: activeEffect, target, type, key }) } } }
3.4 trigger
trigger的運行過程。其實是消費targetMap的依賴,找到依賴后,開始執行任務。
const obj = { a: '1', } trigger(obj, TriggerOpTypes.SET, 'a', '2', '1');
