test('should retrieve readonly values on iteration', () => {
const key1 = {}
const key2 = {}
- const original = new Collection([[key1, {}], [key2, {}]])
+ const original = new Map([[key1, {}], [key2, {}]])
const wrapped: any = readonly(original)
expect(wrapped.size).toBe(2)
for (const [key, value] of wrapped) {
test('should retrieve reactive + readonly values on iteration', () => {
const key1 = {}
const key2 = {}
- const original = reactive(new Collection([[key1, {}], [key2, {}]]))
+ const original = reactive(new Map([[key1, {}], [key2, {}]]))
const wrapped: any = readonly(original)
expect(wrapped.size).toBe(2)
for (const [key, value] of wrapped) {
-import { reactive, readonly, toRaw, ReactiveFlags, Target } from './reactive'
+import {
+ reactive,
+ readonly,
+ toRaw,
+ ReactiveFlags,
+ Target,
+ readonlyMap,
+ reactiveMap
+} from './reactive'
import { TrackOpTypes, TriggerOpTypes } from './operations'
import { track, trigger, ITERATE_KEY } from './effect'
import {
return isReadonly
} else if (
key === ReactiveFlags.RAW &&
- receiver ===
- (isReadonly
- ? target[ReactiveFlags.READONLY]
- : target[ReactiveFlags.REACTIVE])
+ receiver === (isReadonly ? readonlyMap : reactiveMap).get(target)
) {
return target
}
callback: Function,
thisArg?: unknown
) {
- const observed = this
- const target = toRaw(observed)
+ const observed = this as any
+ const target = observed[ReactiveFlags.RAW]
+ const rawTarget = toRaw(target)
const wrap = isReadonly ? toReadonly : isShallow ? toShallow : toReactive
- !isReadonly && track(target, TrackOpTypes.ITERATE, ITERATE_KEY)
- // important: create sure the callback is
- // 1. invoked with the reactive map as `this` and 3rd arg
- // 2. the value received should be a corresponding reactive/readonly.
- function wrappedCallback(value: unknown, key: unknown) {
+ !isReadonly && track(rawTarget, TrackOpTypes.ITERATE, ITERATE_KEY)
+ return target.forEach((value: unknown, key: unknown) => {
+ // important: make sure the callback is
+ // 1. invoked with the reactive map as `this` and 3rd arg
+ // 2. the value received should be a corresponding reactive/readonly.
return callback.call(thisArg, wrap(value), wrap(key), observed)
- }
- return getProto(target).forEach.call(target, wrappedCallback)
+ })
}
}
-import { isObject, toRawType, def, hasOwn } from '@vue/shared'
+import { isObject, toRawType, def } from '@vue/shared'
import {
mutableHandlers,
readonlyHandlers,
SKIP = '__v_skip',
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
- RAW = '__v_raw',
- REACTIVE = '__v_reactive',
- READONLY = '__v_readonly'
+ RAW = '__v_raw'
}
export interface Target {
[ReactiveFlags.IS_REACTIVE]?: boolean
[ReactiveFlags.IS_READONLY]?: boolean
[ReactiveFlags.RAW]?: any
- [ReactiveFlags.REACTIVE]?: any
- [ReactiveFlags.READONLY]?: any
}
+export const reactiveMap = new WeakMap<Target, any>()
+export const readonlyMap = new WeakMap<Target, any>()
+
const enum TargetType {
INVALID = 0,
COMMON = 1,
return target
}
// target already has corresponding Proxy
- const reactiveFlag = isReadonly
- ? ReactiveFlags.READONLY
- : ReactiveFlags.REACTIVE
- if (hasOwn(target, reactiveFlag)) {
- return target[reactiveFlag]
+ const proxyMap = isReadonly ? readonlyMap : reactiveMap
+ const existingProxy = proxyMap.get(target)
+ if (existingProxy) {
+ return existingProxy
}
// only a whitelist of value types can be observed.
const targetType = getTargetType(target)
if (targetType === TargetType.INVALID) {
return target
}
- const observed = new Proxy(
+ const proxy = new Proxy(
target,
targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
)
- def(target, reactiveFlag, observed)
- return observed
+ proxyMap.set(target, proxy)
+ return proxy
}
export function isReactive(value: unknown): boolean {