diff --git a/packages/reactivity/__tests__/effect.spec.ts b/packages/reactivity/__tests__/effect.spec.ts index a322c7209f4..ed23b18446a 100644 --- a/packages/reactivity/__tests__/effect.spec.ts +++ b/packages/reactivity/__tests__/effect.spec.ts @@ -964,5 +964,31 @@ describe('reactivity/effect', () => { m.set(key, 2) expect(fnSpy).toHaveBeenCalledTimes(2) }) + + test('should track hasOwnProperty', () => { + const obj: any = reactive({}) + let has = false + const fnSpy = jest.fn() + + effect(() => { + fnSpy() + has = obj.hasOwnProperty('foo') + }) + expect(fnSpy).toHaveBeenCalledTimes(1) + expect(has).toBe(false) + + obj.foo = 1 + expect(fnSpy).toHaveBeenCalledTimes(2) + expect(has).toBe(true) + + delete obj.foo + expect(fnSpy).toHaveBeenCalledTimes(3) + expect(has).toBe(false) + + // should not trigger on unrelated key + obj.bar = 2 + expect(fnSpy).toHaveBeenCalledTimes(3) + expect(has).toBe(false) + }) }) }) diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts index dfff56f7fc5..46240dba77c 100644 --- a/packages/reactivity/src/baseHandlers.ts +++ b/packages/reactivity/src/baseHandlers.ts @@ -85,6 +85,13 @@ function createArrayInstrumentations() { return instrumentations } +function hasOwnProperty(key: string) { + // @ts-ignore + const obj = toRaw(this) + track(obj, TrackOpTypes.HAS, key) + return obj.hasOwnProperty(key) +} + function createGetter(isReadonly = false, shallow = false) { return function get(target: Target, key: string | symbol, receiver: object) { if (key === ReactiveFlags.IS_REACTIVE) { @@ -110,8 +117,13 @@ function createGetter(isReadonly = false, shallow = false) { const targetIsArray = isArray(target) - if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) { - return Reflect.get(arrayInstrumentations, key, receiver) + if (!isReadonly) { + if (targetIsArray && hasOwn(arrayInstrumentations, key)) { + return Reflect.get(arrayInstrumentations, key, receiver) + } + if (key === 'hasOwnProperty') { + return hasOwnProperty + } } const res = Reflect.get(target, key, receiver)