vue3.2 reactivity 之 baseHandlers , collectionHandlers API源码解析
- --------- baseHandlers ----------
- get
- createGetter
- arrayInstrumentations
- set
- createSetter
- deleteProperty
- has
- ownKeys
- mutableHandlers
- readonlyHandlers
- shallowReactiveHandlers
- shallowReadonlyHandlers
- --------- collectionHandlers----------
- toShallow
- getProto
- mutableCollectionHandlers
- shallowCollectionHandlers
- readonlyCollectionHandlers
- shallowReadonlyCollectionHandlers
- createInstrumentationGetter
- createInstrumentations
- get
- has
- size
- add
- set
- deleteEntry
- clear
- forEach
- createReadonlyMethod
- createIterableMethod
在代码块中我会添加注释,方便大家理解,配合vue文档看效果更佳
本篇针对 /packages/reactivity/src/baseHandlers .ts 与 /packages/reactivity/src/collectionHandlers.ts
--------- baseHandlers ----------
get
首先来看一下所有的get方法定义
const get = /*#__PURE__*/ createGetter()
const shallowGet = /*#__PURE__*/ createGetter(false, true)
const readonlyGet = /*#__PURE__*/ createGetter(true)
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)
可以看到,所有的get方法都由 createGetter创建而来
createGetter
//创建get方法
// isReadonly 是否只读,shallow是否是浅层
function createGetter(isReadonly = false, shallow = false) {
return function get(target: Target, key: string | symbol, receiver: object) {
//当获取 key = __v_isReactive 时,返回 isReadonly取反,因为只有 readonly, reactive
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
// 当获取 key = __v_isReadonly 时,返回 isReadonly
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly
// 当获取 key = __v_raw 时,并且已在对应的proxy缓存map中存在,则直接返回
} else if (
key === ReactiveFlags.RAW &&
receiver ===
(isReadonly ? (shallow ? shallowReadonlyMap : readonlyMap) : (shallow ? shallowReactiveMap : reactiveMap) ).get(target)
) {
return target
}
//判断是否为数组, 实际就是调用 Array.isArray(target)
const targetIsArray = isArray(target)
//不是只读 且 是数组类型 且 key 值 在 **arrayInstrumentations** 中
if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
return Reflect.get(arrayInstrumentations, key, receiver)
}
//拿到结果
const res = Reflect.get(target, key, receiver)
// 判断是否是 symbol
// builtInSymbols: symbol 类 上的一些symbol类型的属性,例如迭代器 symbol.iterator
if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
return res
}
//如果不是只读的,则进行依赖收集
if (!isReadonly) {
track(target, TrackOpTypes.GET, key)
}
//如果是浅层的,则直接返回
if (shallow) {
return res
}
//如果是一个ref
// 如果target不是数组,或者 key不是整数, 则返回 res.value
// 其余情况返回res
if (isRef(res)) {
const shouldUnwrap = !targetIsArray || !isIntegerKey(key)
return shouldUnwrap ? res.value : res
}
if (isObject(res)) {
return isReadonly ? readonly(res) : reactive(res)
}
return res
}
}
判断:key = ReactiveFlags.IS_REACTIVE ,例:在 isReactive, 中被使用。
判断:key = ReactiveFlags.IS_READONLY,例:在 isReadonly 中被使用。
判断:key = ReactiveFlags.RAW ,例:在 toRaw 中被使用。
判断:不是只读 且 是数组类型 且 key 值 在 arrayInstrumentations 中, 则直接返回arrayInstrumentations对应key的结果。(arrayInstrumentations是对数组一些方法的重写,下面会介绍到)。
当以上情况都不满足,则调用Reflect反射先拿到结果res。
builtInSymbols
isNonTrackableKeys
const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`)
{
__proto__: true,
__v_isRef: true,
__isVue: true
}
判断是否是symbol类,是则判断是否在 builtInSymbols中,反之判断是否在isNonTrackableKeys,是则直接返回。
接着判断是否为只读,否则进行依赖收集,判断是否为浅层,是则直接返回。
判断是否为ref,是则 如果 target不是数组,或者 key不是整数,返回res.value
例如:const arr = reactive([ 1,2, ref(3) ]) 这里取 arr[3] 时就返回 3
然后判断res是否为对象,在根据 isReadonly 去判断用 readonly(res) 或者 reactive(res) 进行转换。
也就是当出现嵌套对象时,只有用到的时候才会去把它转化成响应式proxy对象。
arrayInstrumentations
const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations()
function createArrayInstrumentations() {
const instrumentations: Record<string, Function> = {}
// 对下标敏感的方法重写,收集依赖
;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
//获取原始数组
const arr = toRaw(this) as any
//收集每个下标依赖 例:targetMap: { arr: { 0:{ effect }, 1: { effect } } }
for (let i = 0, l = this.length; i < l; i++) {
track(arr, TrackOpTypes.GET, i + '')
}
// 执行对应方法获取值
const res = arr[key](...args)
// 如果未找到,有可能args参数中存在响应式proxy对象,对args遍历进行toRaw,并重新执行
if (res === -1 || res === false) {
return arr[key](...args.map(toRaw))
} else {
return res
}
}
})
//对数组长度敏感的方法进行重写,已防某些情况下出现死循环(因为对length获取或赋值会走依赖的收集与更新)
;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
instrumentations[key] = function (this: unknown[], ...args: unknown[]) {
pauseTracking() // 暂停依赖收集
const res = (toRaw(this) as any)[key].apply(this, args) //执行对应方法
resetTracking() // 重置依赖收集
return res
}
})
return instrumentations
}
对数组长度敏感的方法进行重写,已防某些情况下出现死循环。来解释一下,我们拿push方法举例
const res = (toRaw(this) as any)[key].apply(this, args)
以上apply传进去的this是我们的响应式对象,当push方法执行时,会从this中获取length,以及对length进行更新,假如不暂停依赖的收集。我们看个场景:
set
const set = /*#__PURE__*/ createSetter()
const shallowSet = /*#__PURE__*/ createSetter(true)
createSetter
// 创建set方法, shallow 参数标识是否为浅层
function createSetter(shallow = false) {
return function set(
target: object,
key: string | symbol,
value: unknown,
receiver: object
): boolean {
let oldValue = (target as any)[key] //获取旧值
//非浅层 且 value非只读
if (!shallow && !isReadonly(value)) {
value = toRaw(value)
oldValue = toRaw(oldValue)
//target不是数组, oldValue是ref, value不是ref
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value //赋值操作
return true //返回true结束
}
} else {
// in shallow mode, objects are set as-is regardless of reactive or not
}
// hadKey 进行取值有效判断,即key是否在target上存在
const hadKey =
isArray(target) && isIntegerKey(key)
? Number(key) < target.length
: hasOwn(target, key)
const result = Reflect.set(target, key, value, receiver) //获取结果
// 保证target被代理过
if (target === toRaw(receiver)) {
if (!hadKey) {
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
return result
}
}
首先对oldValue是一个ref进行处理直接 .value赋值, 则会触发ref对应的依赖。
hadkey 判断 key是否在target上,以便 trigger时,通知是 ADD 还是 SET。
deleteProperty
delete 操作符的捕捉器
function deleteProperty(target: object, key: string | symbol): boolean {
const hadKey = hasOwn(target, key) //判断是否属于target
const oldValue = (target as any)[key] //获取旧值
const result = Reflect.deleteProperty(target, key) //结果
//成功且属于target,触发依赖
if (result && hadKey) {
trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
}
return result
}
has
in 操作符的捕捉器
function has(target: object, key: string | symbol): boolean {
const result = Reflect.has(target, key) //结果
// 如果不是Symbol,或者不属于Symbol上的Symbol属性,则收集依赖
if (!isSymbol(key) || !builtInSymbols.has(key)) {
track(target, TrackOpTypes.HAS, key)
}
return result
}
ownKeys
Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器
function ownKeys(target: object): (string | symbol)[] {
//收集依赖
track(target, TrackOpTypes.ITERATE, isArray(target) ? 'length' : ITERATE_KEY)
return Reflect.ownKeys(target)
}
mutableHandlers
export const mutableHandlers: ProxyHandler<object> = {
get,
set,
deleteProperty,
has,
ownKeys
}
readonlyHandlers
export const readonlyHandlers: ProxyHandler<object> = {
get: readonlyGet,
set(target, key) {
if (__DEV__) {
console.warn(
`Set operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
},
deleteProperty(target, key) {
if (__DEV__) {
console.warn(
`Delete operation on key "${String(key)}" failed: target is readonly.`,
target
)
}
return true
}
}
在readonlyHandlers中,set 与 deleteProperty 不做任何操作,就是不允许修改和删除。
在dev环境中会有对应警告。
shallowReactiveHandlers
// extend 是一个工具函数,可以理解为合并对象
export const shallowReactiveHandlers = /*#__PURE__*/ extend(
{},
mutableHandlers,
{
get: shallowGet,
set: shallowSet
}
)
在 mutableHandlers 基础上,将get 和 set 替换成 shallowGet 和 shallowSet
shallowReadonlyHandlers
export const shallowReadonlyHandlers = /*#__PURE__*/ extend(
{},
readonlyHandlers,
{
get: shallowReadonlyGet
}
)
在 readonlyHandlers 基础上,将get 替换成 shallowReadonlyGet
--------- collectionHandlers----------
export type CollectionTypes = IterableCollections | WeakCollections
type IterableCollections = Map<any, any> | Set<any>
type WeakCollections = WeakMap<any, any> | WeakSet<any>
type MapTypes = Map<any, any> | WeakMap<any, any>
type SetTypes = Set<any> | WeakSet<any>
toShallow
const toShallow = <T extends unknown>(value: T): T => value
shallow转换,直接返回value。
getProto
const getProto = <T extends CollectionTypes>(v: T): any =>
Reflect.getPrototypeOf(v)
获取原型的通用方法
mutableCollectionHandlers
shallowCollectionHandlers
readonlyCollectionHandlers
shallowReadonlyCollectionHandlers
export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: /*#__PURE__*/ createInstrumentationGetter(false, false)
}
export const shallowCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: /*#__PURE__*/ createInstrumentationGetter(false, true)
}
export const readonlyCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: /*#__PURE__*/ createInstrumentationGetter(true, false)
}
export const shallowReadonlyCollectionHandlers: ProxyHandler<CollectionTypes> =
{
get: /*#__PURE__*/ createInstrumentationGetter(true, true)
}
所有的Handlers都只有一个get方法,且都有 createInstrumentationGetter 创建。
因为对于 Map,WeakMap,Set,WeakSet, 无论是取值或者是赋值等操作都是调用其方法。
createInstrumentationGetter
// isReadonly 是否只读, shallow 是否浅层
function createInstrumentationGetter(isReadonly: boolean, shallow: boolean) {
//判断使用哪个 Instrumentations
// Instrumentations 由 createInstrumentations创建
// Instrumentations 为 get,set,add,等的方法集
const instrumentations = shallow
? isReadonly
? shallowReadonlyInstrumentations
: shallowInstrumentations
: isReadonly
? readonlyInstrumentations
: mutableInstrumentations
return (
target: CollectionTypes,
key: string | symbol,
receiver: CollectionTypes
) => {
// 这部分与baseHandlers基本一样,对于一些特殊属性进行取值
//获取是否是reactive
if (key === ReactiveFlags.IS_REACTIVE) {
return !isReadonly
//获取是否是readonly
} else if (key === ReactiveFlags.IS_READONLY) {
return isReadonly
//获取是否原始值
} else if (key === ReactiveFlags.RAW) {
return target
}
//第一个参数
//如果 key 在 instrumentations 中,且在target中, 则返回对应的 instrumentations,反之正常返回target
return Reflect.get(
hasOwn(instrumentations, key) && key in target
? instrumentations
: target,
key,
receiver
)
}
}
首先是根据参数获取对应的instrumentations (集合或字典对应的方法集)。
接着return 真正的get函数,进行特殊取值的判断, 在返回反射get时,对第一个参数target进行判断,如果是调用集合或字典上对应的方法,则第一个参数为 instrumentations,否则正常使用target。
目的就是为了能调用 instrumentations 中各种重写后的方法。
接着我们看 Instrumentations 的由来 。
const [
mutableInstrumentations,
readonlyInstrumentations,
shallowInstrumentations,
shallowReadonlyInstrumentations
] = /* #__PURE__*/ createInstrumentations()
由createInstrumentations 创建而来的数组包裹。
createInstrumentations
function createInstrumentations() {
// 定义 mutableInstrumentations
const mutableInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key)
},
get size() {
return size(this as unknown as IterableCollections)
},
has,
add,
set,
delete: deleteEntry,
clear,
forEach: createForEach(false, false)
}
// 定义 shallowInstrumentations
const shallowInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, false, true)
},
get size() {
return size(this as unknown as IterableCollections)
},
has,
add,
set,
delete: deleteEntry,
clear,
forEach: createForEach(false, true)
}
// 定义 readonlyInstrumentations
const readonlyInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, true)
},
get size() {
return size(this as unknown as IterableCollections, true)
},
has(this: MapTypes, key: unknown) {
return has.call(this, key, true)
},
add: createReadonlyMethod(TriggerOpTypes.ADD),
set: createReadonlyMethod(TriggerOpTypes.SET),
delete: createReadonlyMethod(TriggerOpTypes.DELETE),
clear: createReadonlyMethod(TriggerOpTypes.CLEAR),
forEach: createForEach(true, false)
}
// 定义 shallowReadonlyInstrumentations
const shallowReadonlyInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, true, true)
},
get size() {
return size(this as unknown as IterableCollections, true)
},
has(this: MapTypes, key: unknown) {
return has.call(this, key, true)
},
add: createReadonlyMethod(TriggerOpTypes.ADD),
set: createReadonlyMethod(TriggerOpTypes.SET),
delete: createReadonlyMethod(TriggerOpTypes.DELETE),
clear: createReadonlyMethod(TriggerOpTypes.CLEAR),
forEach: createForEach(true, true)
}
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]
iteratorMethods.forEach(method => {
mutableInstrumentations[method as string] = createIterableMethod(
method,
false,
false
)
readonlyInstrumentations[method as string] = createIterableMethod(
method,
true,
false
)
shallowInstrumentations[method as string] = createIterableMethod(
method,
false,
true
)
shallowReadonlyInstrumentations[method as string] = createIterableMethod(
method,
true,
true
)
})
return [
mutableInstrumentations,
readonlyInstrumentations,
shallowInstrumentations,
shallowReadonlyInstrumentations
]
}
可以看到,createInstrumentations 主要就是对各种 Instrumentations 进行各种方法的重写 (get,set,has,add,clear,delete,forEach),以及迭代方法的重写(keys,values,entries,Symbol.iterator)。接着我们在逐步介绍其中的方法。
get
function get(
target: MapTypes, // Map or WeakMAp
key: unknown, // key
isReadonly = false, //是否只读
isShallow = false //是否浅层
) {
// 例如:reactive(Map) 中的 Map; readonly(reactive(Map)) 中的 reactive(Map)
target = (target as any)[ReactiveFlags.RAW]
// target 为 map 则返回 Map; target 为 reactive(Map) 则返回 Map
const rawTarget = toRaw(target)
const rawKey = toRaw(key) //获取key原始值
// 当key不等于rawkey; 例如:key = reactive({}) 时, rawKey = {}
if (key !== rawKey) {
//不是只读则对 rawTarget 中的 key 进行依赖收集
!isReadonly && track(rawTarget, TrackOpTypes.GET, key)
}
//不是只读则对 rawTarget 中的 rawKey 进行依赖收集
!isReadonly && track(rawTarget, TrackOpTypes.GET, rawKey)
const { has } = getProto(rawTarget) //获取rawTarget原型中的has
//获取对应转换方法
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
/*
当 key存在于rawTarget时,获取值并转换成对应的响应式对象
例如:
const map = new Map( [ ['name', 'loookooo'] ] )
const reactiveMap = reactive(map)
reactiveMap.get('name')
此时 map 的结构等于 { 'name': 'loookooo' }
target = map rawTarget = map
key = 'name' rawkey = 'name'
*/
if (has.call(rawTarget, key)) {
return wrap(target.get(key))
/*
当 key不存在于rawTarget时, rawKey存在于rawTarget时,获取值并转换成对应的响应式对象
例如:
const map = new Map()
const reactiveMap = reactive(map)
const reactiveKey = reactive({ key: 'key' })
const reactiveValue = reactive({ value: 'value' })
reactiveMap.set(reactiveKey, reactiveValue )
reactiveMap.get(reactiveKey)
此时 map 的结构等于 { { key: 'key'} : { value: 'value'} }
target = map rawTarget = map
key = reactiveKey rawkey = { key: 'key' }
*/
} else if (has.call(rawTarget, rawKey)) {
return wrap(target.get(rawKey))
/*
当 key不存在于rawTarget时, rawKey不存在于rawTarget时,
target !== rawTarget 调用 target.get(key)
例如:
const map = new Map()
const key = { key: 'key' }
const value = { value: 'value' }
const reactiveKey = reactive(key)
const reactiveValue = reactive(value)
map.set(reactiveKey, reactiveValue)
const reactiveMap = reactive(map)
const readonlyMap = readonly(reactiveMap)
readonlyMap.get(key)
此时 map 的结构等于 { reactiveKey : reactiveValue }
target = reactiveMap rawTarget = map
key = { key: 'key' } rawkey = { key: 'key' }
*/
} else if (target !== rawTarget) {
// readonly(reactive(Map))
// 确保嵌套的反应式 `Map` 可以为自己进行跟踪
target.get(key)
}
}
获取rawTarget时会经过两次获取原始值,是为了出现readonly(reactive(Map)) 的情况。
当key不等于rawkey时,对key进行依赖收集。 对rawkey进行依赖收集
例如:key = reactive({}),rawkey = {},这时当key或者rawkey发生变化时,都会触发各自依赖。
接着就是对各种情况进行处理,代码块中有详细分析。
has
function has(this: CollectionTypes, key: unknown, isReadonly = false): boolean {
const target = (this as any)[ReactiveFlags.RAW]
const rawTarget = toRaw(target)
const rawKey = toRaw(key)
if (key !== rawKey) {
!isReadonly && track(rawTarget, TrackOpTypes.HAS, key)
}
!isReadonly && track(rawTarget, TrackOpTypes.HAS, rawKey)
/*
const reactiveKey = reactive({ key: 'key' })
const map = new Map()
const reactiveMap = reactive(map)
reactiveMap.set(reactiveKey, 'value')
reactiveKey in reactiveMap
此时: map 结构 = { { key: 'key' } : 'value' }
target = map rawTarget = map
key = reactiveKey rawkey = {key:'key'}
*/
return key === rawKey
? target.has(key)
: target.has(key) || target.has(rawKey)
}
前面的处理与get差不多,都是获取原始值。然后对key和rawkey做判断,进行依赖收集。
返回时,当key不等于rawkey时,has(key) 不存在则返回 has(rawkey) , 代码块中已举例
size
function size(target: IterableCollections, isReadonly = false) {
target = (target as any)[ReactiveFlags.RAW]
!isReadonly && track(toRaw(target), TrackOpTypes.ITERATE, ITERATE_KEY)
return Reflect.get(target, 'size', target)
}
export const ITERATE_KEY = Symbol(__DEV__ ? 'iterate' : '')
调用size的时候对ITERATE_KEY进行依赖收集。在调用一些迭代方法的时候会触发ITERATE_KEY收集的依赖,例如 keys,values等。
add
function add(this: SetTypes, value: unknown) {
value = toRaw(value)
const target = toRaw(this)
const proto = getProto(target)
const hadKey = proto.has.call(target, value)
if (!hadKey) {
target.add(value)
trigger(target, TriggerOpTypes.ADD, value, value)
}
return this
}
获取原始值,判断是否已存在,不存在则触发ADD操作类型的依赖。
set
function set(this: MapTypes, key: unknown, value: unknown) {
value = toRaw(value) //获取value原始值
const target = toRaw(this) //获取this原始值
const { has, get } = getProto(target) //获取target原型的 has,get
let hadKey = has.call(target, key) //判断target是否存在key
//如果不存在
/*
场景:
const key = { key: 'key' }
const map = new Map( [ key, 'value' ] )
const reactiveKey = reactive(key)
const reactiveMap = reactive( map )
reactiveMap.set(reactiveKey, 'newValue')
此时:
value = 'newValue' target = map
key = reactiveKey
reactiveKey 不存在于 map
则 key = toRaw(reactiveKey) = { key: 'key' }
hadKey = has.call(map, { key: 'key' }) = true
*/
if (!hadKey) {
key = toRaw(key) //获取key原始值,并赋值
hadKey = has.cal(target, key) // 判断target是否存在key原始值
} else if (__DEV__) {
checkIdentityKeys(target, has, key)
}
//获取旧值
const oldValue = get.call(target, key)
//调用原始值target的set操作
target.set(key, value)
//不存在,则触发ADD操作类型依赖
if (!hadKey) {
trigger(target, TriggerOpTypes.ADD, key, value)
//存在且新旧值不相同,则触发SET操作类型依赖
} else if (hasChanged(value, oldValue)) {
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
return this
}
set时先判断key是否在target 原始值里,否则对key原始值再进行一次判断。
依据判断结果来触发ADD或者SET的操作类型依赖。
deleteEntry
function deleteEntry(this: CollectionTypes, key: unknown) {
const target = toRaw(this) //获取this原始值
const { has, get } = getProto(target) //获取原型的 has,get
let hadKey = has.call(target, key) // 判断是否存在 key
//不存在则对key原始值进一次判断
if (!hadKey) {
key = toRaw(ke)
hadKey = has.call(target, key)
} else if (__DEV__) {
checkIdentityKeys(target, has, key)
}
//判断get方法是否存在,是则获取旧值。Set,WeakSet 没有 get 和 set 方法,所以旧值为undefined
const oldValue = get ? get.call(target, key) : undefined
// 执行delete操作,获取操作结果
const result = target.delete(key)
if (hadKey) {
trigger(target, TriggerOpTypes.DELETE, key, undefined, oldValue)
}
return result
}
判断是否存在,获取旧值时区分Map,WeakMap 于 Set, WeakSet。
当存在时,则触发对应依赖。
clear
function clear(this: IterableCollections) {
const target = toRaw(this) //获取this原始值
const hadItems = target.size !== 0 //判断target中是否有元素
//生产环境下为undefined
const oldTarget = __DEV__
? isMap(target)
? new Map(target)
: new Set(target)
: undefined
// 执行clear操作,获取操作结果
const result = target.clear()
//如果有元素,则触发对应依赖
if (hadItems) {
trigger(target, TriggerOpTypes.CLEAR, undefined, undefined, oldTarget)
}
return result
}
forEach
function createForEach(isReadonly: boolean, isShallow: boolean) {
return function forEach(
this: IterableCollections,
callback: Function,
thisArg?: unknown
) {
const observed = this as any
const target = observed[ReactiveFlags.RAW] //获取 observed.__v_raw
const rawTarget = toRaw(target) //获取 target 原始值
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
//对 ITERATE_KEY 进行依赖收集
!isReadonly && track(rawTarget, TrackOpTypes.ITERATE, ITERATE_KEY)
//执行forEach并返回操作结果
return target.forEach((value: unknown, key: unknown) => {
//执行callback,转换value,key为响应式对象并带入
return callback.call(thisArg, wrap(value), wrap(key), observed)
})
}
}
与前面size一样, forEach同样会对 ITERATE_KEY (迭代key) 进行依赖收集。
createReadonlyMethod
function createReadonlyMethod(type: TriggerOpTypes): Function {
return function (this: CollectionTypes, ...args: unknown[]) {
if (__DEV__) {
const key = args[0] ? `on key "${args[0]}" ` : ``
console.warn(
`${capitalize(type)} operation ${key}failed: target is readonly.`,
toRaw(this)
)
}
return type === TriggerOpTypes.DELETE ? false : this
}
}
创建只读方法。不做任何操作,直接返回false或this
createIterableMethod
function createIterableMethod(
method: string | symbol,
isReadonly: boolean,
isShallow: boolean
) {
return function (
this: IterableCollections,
...args: unknown[]
): Iterable & Iterator {
const target = (this as any)[ReactiveFlags.RAW]
const rawTarget = toRaw(target)
const targetIsMap = isMap(rawTarget) //判断是否是map
//判断是否是成对遍历,即 key 与 value 一起
const isPair =
method === 'entries' || (method === Symbol.iterator && targetIsMap)
//是否是keys方法且是Map类型
const isKeyOnly = method === 'keys' && targetIsMap
//执行操作记录结果
const innerIterator = target[method](...args)
const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
//不是只读则对迭代key进行依赖收集
!isReadonly &&
track(
rawTarget,
TrackOpTypes.ITERATE,
isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY
)
// 包装迭代器
return {
// iterator protocol
next() {
const { value, done } = innerIterator.next() //获取真实的结果
return done
? { value, done }
: {
//判断是否成对,返回相应的响应式值
value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value),
done
}
},
[Symbol.iterator]() {
return this
}
}
}
}
判断遍历的类型是 key和value,key,value。
非只读时收集依赖。
返回包装迭代器,其中获取真是遍历结果,并包装返回对应的响应式结果。