diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts index 45ecfa6d3..259b44a1e 100644 --- a/packages/reactivity/src/baseHandlers.ts +++ b/packages/reactivity/src/baseHandlers.ts @@ -26,7 +26,6 @@ import { hasChanged, isArray, isIntegerKey, - extend, makeMap } from '@vue/shared' import { isRef } from './ref' @@ -45,11 +44,6 @@ const builtInSymbols = new Set( .filter(isSymbol) ) -const get = /*#__PURE__*/ createGetter() -const shallowGet = /*#__PURE__*/ createGetter(false, true) -const readonlyGet = /*#__PURE__*/ createGetter(true) -const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true) - const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations() function createArrayInstrumentations() { @@ -91,8 +85,15 @@ function hasOwnProperty(this: object, key: string) { return obj.hasOwnProperty(key) } -function createGetter(isReadonly = false, shallow = false) { - return function get(target: Target, key: string | symbol, receiver: object) { +class BaseReactiveHandler implements ProxyHandler { + constructor( + protected readonly _isReadonly = false, + protected readonly _shallow = false + ) {} + + get(target: Target, key: string | symbol, receiver: object) { + const isReadonly = this._isReadonly, + shallow = this._shallow if (key === ReactiveFlags.IS_REACTIVE) { return !isReadonly } else if (key === ReactiveFlags.IS_READONLY) { @@ -155,11 +156,12 @@ function createGetter(isReadonly = false, shallow = false) { } } -const set = /*#__PURE__*/ createSetter() -const shallowSet = /*#__PURE__*/ createSetter(true) +class MutableReactiveHandler extends BaseReactiveHandler { + constructor(shallow = false) { + super(false, shallow) + } -function createSetter(shallow = false) { - return function set( + set( target: object, key: string | symbol, value: unknown, @@ -169,7 +171,7 @@ function createSetter(shallow = false) { if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) { return false } - if (!shallow) { + if (!this._shallow) { if (!isShallow(value) && !isReadonly(value)) { oldValue = toRaw(oldValue) value = toRaw(value) @@ -197,42 +199,40 @@ function createSetter(shallow = false) { } return result } -} -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) + 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 } - 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) + 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 + } + ownKeys(target: object): (string | symbol)[] { + track( + target, + TrackOpTypes.ITERATE, + isArray(target) ? 'length' : ITERATE_KEY + ) + return Reflect.ownKeys(target) } - return result } -function ownKeys(target: object): (string | symbol)[] { - track(target, TrackOpTypes.ITERATE, isArray(target) ? 'length' : ITERATE_KEY) - return Reflect.ownKeys(target) -} +class ReadonlyReactiveHandler extends BaseReactiveHandler { + constructor(shallow = false) { + super(true, shallow) + } -export const mutableHandlers: ProxyHandler = { - get, - set, - deleteProperty, - has, - ownKeys -} - -export const readonlyHandlers: ProxyHandler = { - get: readonlyGet, - set(target, key) { + set(target: object, key: string | symbol) { if (__DEV__) { warn( `Set operation on key "${String(key)}" failed: target is readonly.`, @@ -240,8 +240,9 @@ export const readonlyHandlers: ProxyHandler = { ) } return true - }, - deleteProperty(target, key) { + } + + deleteProperty(target: object, key: string | symbol) { if (__DEV__) { warn( `Delete operation on key "${String(key)}" failed: target is readonly.`, @@ -252,22 +253,18 @@ export const readonlyHandlers: ProxyHandler = { } } -export const shallowReactiveHandlers = /*#__PURE__*/ extend( - {}, - mutableHandlers, - { - get: shallowGet, - set: shallowSet - } +export const mutableHandlers: ProxyHandler = + /*#__PURE__*/ new MutableReactiveHandler() + +export const readonlyHandlers: ProxyHandler = + /*#__PURE__*/ new ReadonlyReactiveHandler() + +export const shallowReactiveHandlers = /*#__PURE__*/ new MutableReactiveHandler( + true ) // Props handlers are special in the sense that it should not unwrap top-level // refs (in order to allow refs to be explicitly passed down), but should // retain the reactivity of the normal readonly object. -export const shallowReadonlyHandlers = /*#__PURE__*/ extend( - {}, - readonlyHandlers, - { - get: shallowReadonlyGet - } -) +export const shallowReadonlyHandlers = + /*#__PURE__*/ new ReadonlyReactiveHandler(true)