源码位置: https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/reactive.ts
reactive 方法 接收一个对象,返回 对象深代理,通过 createReactiveObject
方法
对象的 reactive
代理,会被缓存,所以对同一个对象执行多次 reactive
返回的是同一个值 示例:
1 2 3 4 5 6 setup ( ) { const a = {b : 12 } const reactive1 = Vue.reactive(a) const reactive2 = Vue.reactive(a) console .log(reactive1 === reactive2) }
如果对象是 readonly
类型的,就返回对象本身 示例:
1 2 3 4 5 6 setup ( ) { const a = {b : 12 } const readonly = Vue.readonly(a) const reactive = Vue.reactive(readonly ) console .log(readonly === reactive) }
1 2 3 4 5 6 7 8 9 10 11 export function reactive (target: object ) { if (target && (target as Target)[ReactiveFlags.IS_READONLY]) { return target } return createReactiveObject( target, false , mutableHandlers, mutableCollectionHandlers ) }
mutableHandlers 在 target
是一个正常的 Object
或者 Array
时,使用这个对象做 proxy
的 handle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 const get = createGetter() const set = createSetter() function deleteProperty (target: object , key: string | symbol ): boolean { const hadKey = hasOwn(target, key) const oldValue = (target as any )[key] const result = Reflect .deleteProperty(target, key) if (result && hadKey) { trigger(target, TriggerOpTypes.DELETE, key, undefined , oldValue) } return result } function has (target: object , key: string | symbol ): boolean { const result = Reflect .has(target, key) if (!isSymbol(key) || !builtInSymbols.has(key)) { track(target, TrackOpTypes.HAS, key) } return result } function ownKeys (target: object ): (string | number | symbol )[] { track(target, TrackOpTypes.ITERATE, isArray(target) ? 'length' : ITERATE_KEY) return Reflect .ownKeys(target) } export const mutableHandlers: ProxyHandler<object > = { get, set, deleteProperty, has, ownKeys }
createGetter 参数接收 isReadonly
是否只读, shallow
是否只做前代理, 返回一个 get
函数
当返回值时一个对象,并且 shallow
为 false 时,会对返回值再做一次 readonly
或者 reactive
处理,实现深代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 function createGetter (isReadonly = false , shallow = false ) { return function get (target: Target, key: string | symbol, receiver: object ) { if (key === ReactiveFlags.IS_REACTIVE) { return !isReadonly } else if (key === ReactiveFlags.IS_READONLY) { return isReadonly } else if ( key === ReactiveFlags.RAW && receiver === (isReadonly ? readonlyMap : reactiveMap).get(target) ) { return target } const targetIsArray = isArray(target) if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) { return Reflect .get(arrayInstrumentations, key, receiver) } const res = Reflect .get(target, key, receiver) if ( isSymbol(key) ? builtInSymbols.has(key as symbol) : key === `__proto__` || key === `__v_isRef` ) { return res } if (!isReadonly) { track(target, TrackOpTypes.GET, key) } if (shallow) { return 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 } }
这里用到了一个特殊的值 arrayInstrumentations
这个值表示需要特殊处理的 Array
的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const arrayInstrumentations: Record<string , Function > = {};(['includes' , 'indexOf' , 'lastIndexOf' ] as const ).forEach(key => { const method = Array .prototype[key] as any arrayInstrumentations[key] = function (this : unknown[], ...args: unknown[] ) { const arr = toRaw(this ) for (let i = 0 , l = this .length; i < l; i++) { track(arr, TrackOpTypes.GET, i + '' ) } const res = method.apply(arr, args) if (res === -1 || res === false ) { return method.apply(arr, args.map(toRaw)) } else { return res } } }) ;(['push' , 'pop' , 'shift' , 'unshift' , 'splice' ] as const ).forEach(key => { const method = Array .prototype[key] as any arrayInstrumentations[key] = function (this : unknown[], ...args: unknown[] ) { pauseTracking() const res = method.apply(this , args) resetTracking() return res } })
createSetter 函数接收一个参数 shallow
,是否只做浅代理,返回一个 set
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 function createSetter (shallow = false ) { return function set ( target: object , key: string | symbol, value: unknown, receiver: object ): boolean { const oldValue = (target as any )[key] if (!shallow) { value = toRaw(value) if (!isArray(target) && isRef(oldValue) && !isRef(value)) { oldValue.value = value return true } } else { } const hadKey = isArray(target) && isIntegerKey(key) ? Number (key) < target.length : hasOwn(target, key) const result = Reflect .set(target, key, value, receiver) 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 } }
mutableCollectionHandlers 1 2 3 export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = { get : createInstrumentationGetter(false , false ) }
createInstrumentationGetter 接收两个参数 isReadonly
是否只读和 shallow
是否浅代理
返回一个 get
方法,这里是对 Map.
的代理,get
方法中对 set
/has
…方法做了处理,通过 instrumentations
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 function createInstrumentationGetter (isReadonly: boolean , shallow: boolean ) { const instrumentations = shallow ? shallowInstrumentations : isReadonly ? readonlyInstrumentations : mutableInstrumentations return ( target: CollectionTypes, key: string | symbol, receiver: CollectionTypes ) => { if (key === ReactiveFlags.IS_REACTIVE) { return !isReadonly } else if (key === ReactiveFlags.IS_READONLY) { return isReadonly } else if (key === ReactiveFlags.RAW) { return target } return Reflect .get( hasOwn(instrumentations, key) && key in target ? instrumentations : target, key, receiver ) } }
instrumentations => mutableInstrumentations 返回了一个 handle
的对象,对象方法中的 this
,都是指向 reactive
对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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 ) } const iteratorMethods = ['keys' , 'values' , 'entries' , Symbol .iterator]iteratorMethods.forEach(method => { mutableInstrumentations[method as string ] = createIterableMethod( method, false , false ) })
get 代理 get
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 function get ( target: MapTypes, key: unknown, isReadonly = false , isShallow = false ) { target = (target as any )[ReactiveFlags.RAW] const rawTarget = toRaw(target) const rawKey = toRaw(key) if (key !== rawKey) { !isReadonly && track(rawTarget, TrackOpTypes.GET, key) } !isReadonly && track(rawTarget, TrackOpTypes.GET, rawKey) const { has } = getProto(rawTarget) const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive if (has.call(rawTarget, key)) { return wrap(target.get(key)) } else if (has.call(rawTarget, rawKey)) { return wrap(target.get(rawKey)) } }
toReactive 获取到最终要返回的值的方法,如果是对象/数组类型,返回一个 reactive 类型,否则返回原始值
1 2 const toReactive = <T extends unknown > (value: T): T => isObject(value) ? reactive(value) : value
size 拦截 .size
的获取
1 2 3 4 5 6 7 8 9 10 11 12 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) }
has 拦截 has
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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) return key === rawKey ? target.has(key) : target.has(key) || target.has(rawKey) }
add 拦截 Set
/WeakSet
的 add 操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function add (this : SetTypes, value: unknown ) { value = toRaw(value) const target = toRaw(this ) const proto = getProto(target) const hadKey = proto.has.call(target, value) target.add(value) if (!hadKey) { trigger(target, TriggerOpTypes.ADD, value, value) } return this }
set 拦截 Map
和 WeakMap
的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 function set (this : MapTypes, key: unknown, value: unknown ) { value = toRaw(value) const target = toRaw(this ) const { has, get } = getProto(target) let hadKey = has.call(target, key) if (!hadKey) { key = toRaw(key) hadKey = has.call(target, key) } else if (__DEV__) { checkIdentityKeys(target, has, key) } const oldValue = get.call(target, key) target.set(key, value) if (!hadKey) { trigger(target, TriggerOpTypes.ADD, key, value) } else if (hasChanged(value, oldValue)) { trigger(target, TriggerOpTypes.SET, key, value, oldValue) } return this }
delete 拦截 delete
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 function deleteEntry (this : CollectionTypes, key: unknown ) { const target = toRaw(this ) const { has, get } = getProto(target) let hadKey = has.call(target, key) if (!hadKey) { key = toRaw(key) hadKey = has.call(target, key) } else if (__DEV__) { checkIdentityKeys(target, has, key) } const oldValue = get ? get.call(target, key) : undefined const result = target.delete(key) if (hadKey) { trigger(target, TriggerOpTypes.DELETE, key, undefined , oldValue) } return result }
clear 拦截 clear
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function clear (this : IterableCollections ) { const target = toRaw(this ) const hadItems = target.size !== 0 const oldTarget = __DEV__ ? isMap(target) ? new Map (target) : new Set (target) : undefined const result = target.clear() if (hadItems) { trigger(target, TriggerOpTypes.CLEAR, undefined , undefined , oldTarget) } return result }
forEach 拦截 forEach
操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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] const rawTarget = toRaw(target) const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive !isReadonly && track(rawTarget, TrackOpTypes.ITERATE, ITERATE_KEY) return target.forEach((value: unknown, key: unknown ) => { return callback.call(thisArg, wrap(value), wrap(key), observed) }) } }
keys 、values、entries createIterableMethod 返回一个方法 拦截 iterate
操作,返回一个遍历器,for of
遍历就是基于遍历器实现的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 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) const isPair = method === 'entries' || (method === Symbol .iterator && targetIsMap) const isKeyOnly = method === 'keys' && targetIsMap const innerIterator = target[method](...args) const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive !isReadonly && track( rawTarget, TrackOpTypes.ITERATE, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY ) return { 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 } } } }
shallowReactive 方法 参数接收一个对象,返回对象的浅代理,通过 createReactiveObject
方法
1 2 3 4 5 6 7 8 export function shallowReactive <T extends object >(target: T ): T { return createReactiveObject( target, false , shallowReactiveHandlers, shallowCollectionHandlers ) }
shallowReactiveHandlers 1 2 3 4 5 6 7 8 export const shallowReactiveHandlers: ProxyHandler<object > = extend( {}, mutableHandlers, { get : shallowGet, set : shallowSet } )
用了新的 get
和 set
方法
1 2 const shallowGet = createGetter(false , true )const shallowSet = createSetter(true )
用了上面提到的 createGetter
和 createSetter
方法
shallowCollectionHandlers 1 2 3 export const shallowCollectionHandlers: ProxyHandler<CollectionTypes> = { get : createInstrumentationGetter(false , true ) }
用的还是上面提到的 createInstrumentationGetter
方法
readonly 方法 参数接收一个对象,返回一个只读 readonly
对象,通过 createReactiveObject
方法
1 2 3 4 5 6 7 8 9 10 export function readonly <T extends object >( target: T ): DeepReadonly <UnwrapNestedRefs <T >> { return createReactiveObject( target, true , readonlyHandlers, readonlyCollectionHandlers ) }
readonlyHandlers 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 } }
get
方法 readonlyGet
1 const readonlyGet = createGetter(true )
使用的是上面提到的 createGetter
方法
readonlyCollectionHandlers 1 2 3 export const readonlyCollectionHandlers: ProxyHandler<CollectionTypes> = { get : createInstrumentationGetter(true , false ) }
用的 createInstrumentationGetter
方法,创建的 handle
对象
shallowReadonly 方法 参数接收一个对象,返回一个只读 readonly
的对象,这个只读,只针对对象的第一层,不做深层的代理, 通过 createReactiveObject
方法
1 2 3 4 5 6 7 8 9 10 export function shallowReadonly <T extends object >( target: T ): Readonly < { [K in keyof T]: UnwrapNestedRefs<T[K]> }> { return createReactiveObject( target, true , shallowReadonlyHandlers, readonlyCollectionHandlers ) }
shallowReadonlyHandlers 1 2 3 4 5 6 7 export const shallowReadonlyHandlers: ProxyHandler<object > = extend( {}, readonlyHandlers, { get : shallowReadonlyGet } )
get
方法 shallowReadonlyGet
1 const shallowReadonlyGet = createGetter(true , true )
readonlyCollectionHandlers 1 2 3 export const readonlyCollectionHandlers: ProxyHandler<CollectionTypes> = { get : createInstrumentationGetter(true , false ) }
上面已经提到过
createReactiveObject 方法 参数
参数 描述 target 需要代理的源数据(一般是对象,可以是Map/Set/WeakMap/WeakSet) isReadonly 是否创建只读对象 baseHandlers target 是 Object/Array 时,proxy 的 handle 对象 collectionHandlers target 是 Map/Set/WeakMap/WeakSet时,proxy 的 handle 对象
返回一个 proxy
对象,会对返回的 proxy
和 target
做一个缓存,如果对同一个对象多次调用该方法,获取到的是同一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 function createReactiveObject ( target: Target, isReadonly: boolean , baseHandlers: ProxyHandler<any >, collectionHandlers: ProxyHandler<any > ) { if (!isObject(target)) { if (__DEV__) { console .warn(`value cannot be made reactive: ${String (target)} ` ) } return target } if ( target[ReactiveFlags.RAW] && !(isReadonly && target[ReactiveFlags.IS_REACTIVE]) ) { return target } const proxyMap = isReadonly ? readonlyMap : reactiveMap const existingProxy = proxyMap.get(target) if (existingProxy) { return existingProxy } const targetType = getTargetType(target) if (targetType === TargetType.INVALID) { return target } const proxy = new Proxy ( target, targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers ) proxyMap.set(target, proxy) return proxy }
isReactive 方法 通过 ReactiveFlags.IS_REACTIVE
/ __v_isReactive
属性判断是不是 reactive
对象,这个对象的获取在 proxy
的 handle
中做了处理
1 2 3 4 5 6 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 setup ( ) { const b = Vue.reactive({a : 123 }) console .log(Vue.isReactive(b)) console .log(Vue.isReactive({__v_isReactive : true })) console .log(Vue.isReactive({__v_isReactive : 1 })) }
isReadonly 方法 通过 ReactiveFlags.IS_READONLY
/ __v_isReadonly
判断是否是 readonly
类型
1 2 3 export function isReadonly (value: unknown ): boolean { return !!(value && (value as Target)[ReactiveFlags.IS_READONLY]) }
示例:
1 2 3 4 5 6 setup ( ) { const b = Vue.readonly({a : 123 }) console .log(Vue.isReadonly(b)) console .log(Vue.isReadonly({__v_isReadonly : true })) console .log(Vue.isReadonly({__v_isReadonly : 1 })) }
isProxy 方法 判断数据是不是 reactive
或者 readonly
类型的数据
1 2 3 export function isProxy (value: unknown ): boolean { return isReactive(value) || isReadonly(value) }
示例:
1 2 3 4 5 6 7 8 setup ( ) { const a = Vue.reactive({a : 123 }) const b = Vue.readonly({a : 123 }) console .log(Vue.isProxy(a)) console .log(Vue.isProxy(b)) console .log(Vue.isProxy({__v_isReadonly : true })) console .log(Vue.isProxy({__v_isReactive : true })) }
toRaw 方法 方法接收一个参数,如果参数是 reactive
/ readonly
对象会返回 reactive
对象的原始值,如果不是 reactive
对象,就返回接收的参数
ReactiveFlags.RAW
在 reactive
对象的 get
方法中做了处理
1 2 3 4 5 export function toRaw <T >(observed: T ): T { return ( (observed && toRaw((observed as Target)[ReactiveFlags.RAW])) || observed ) }
示例:
1 2 3 4 5 6 7 8 setup ( ) { const a = Vue.reactive({a : 123 }) const b = Vue.readonly({b : 123 }) console .log(Vue.toRaw(a)) console .log(Vue.toRaw(b)) console .log(Vue.toRaw({__v_isReadonly : true })) console .log(Vue.toRaw({__v_isReactive : true })) }
markRaw 方法 接收一个参数对象,标记这个对象是不需要代理的,通过 ReactiveFlags.SKIP
/ __v_skip
实现,会给对象添加一个 __v_skip
属性,值是 true
1 2 3 4 export function markRaw <T extends object >(value: T ): T { def(value, ReactiveFlags.SKIP, true ) return value }
示例:
1 2 3 4 5 6 7 setup ( ) { const a = Vue.markRaw({a : 123 }) console .log(a) console .log(Vue.reactive({a : 123 })) console .log(Vue.reactive(a)) console .log(Vue.reactive({__v_skip : true })) }