Skip to content

Commit

Permalink
fix(reactivity): use WeakMap for proxy/raw checks, compat with non-ex…
Browse files Browse the repository at this point in the history
…tensible objects

fix vuejs#12799
close vuejs#12798
  • Loading branch information
yyx990803 committed Oct 11, 2022
1 parent 27eed82 commit 4a0d88e
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 8 deletions.
4 changes: 3 additions & 1 deletion src/core/observer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
noop
} from '../util/index'
import { isReadonly, isRef, TrackOpTypes, TriggerOpTypes } from '../../v3'
import { rawMap } from '../../v3/reactivity/reactive'

const arrayKeys = Object.getOwnPropertyNames(arrayMethods)

Expand Down Expand Up @@ -118,7 +119,8 @@ export function observe(
(ssrMockReactivity || !isServerRendering()) &&
(isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value.__v_skip /* ReactiveFlags.SKIP */
!value.__v_skip /* ReactiveFlags.SKIP */ &&
!rawMap.has(value)
) {
ob = new Observer(value, shallow, ssrMockReactivity)
}
Expand Down
9 changes: 7 additions & 2 deletions src/v3/reactivity/reactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import {
isPrimitive,
warn,
toRawType,
isServerRendering
isServerRendering,
isObject
} from 'core/util'
import type { Ref, UnwrapRefSimple, RawSymbol } from './ref'

export const rawMap = new WeakMap()

export const enum ReactiveFlags {
SKIP = '__v_skip',
IS_READONLY = '__v_isReadonly',
Expand Down Expand Up @@ -119,7 +122,9 @@ export function toRaw<T>(observed: T): T {
export function markRaw<T extends object>(
value: T
): T & { [RawSymbol]?: true } {
def(value, ReactiveFlags.SKIP, true)
if (isObject(value)) {
rawMap.set(value, true)
}
return value
}

Expand Down
10 changes: 5 additions & 5 deletions src/v3/reactivity/readonly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export type DeepReadonly<T> = T extends Builtin
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: Readonly<T>

const rawToReadonlyFlag = `__v_rawToReadonly`
const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly`
const rawToReadonlyMap = new WeakMap()
const rawToShallowReadonlyMap = new WeakMap()

export function readonly<T extends object>(
target: T
Expand Down Expand Up @@ -63,14 +63,14 @@ function createReadonly(target: any, shallow: boolean) {
}

// already has a readonly proxy
const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag
const existingProxy = target[existingFlag]
const map = shallow ? rawToShallowReadonlyMap : rawToReadonlyMap
const existingProxy = map.get(target)
if (existingProxy) {
return existingProxy
}

const proxy = Object.create(Object.getPrototypeOf(target))
def(target, existingFlag, proxy)
map.set(target, proxy)

def(proxy, ReactiveFlags.IS_READONLY, true)
def(proxy, ReactiveFlags.RAW, target)
Expand Down
6 changes: 6 additions & 0 deletions test/unit/features/v3/reactivity/reactive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,12 @@ describe('reactivity/reactive', () => {
expect(isReactive(obj.bar)).toBe(false)
})

test('markRaw on non-extensible objects', () => {
const foo = Object.freeze({})
markRaw(foo)
expect(isReactive(reactive(foo))).toBe(false)
})

test('should not observe non-extensible objects', () => {
const obj = reactive({
foo: Object.preventExtensions({ a: 1 }),
Expand Down
7 changes: 7 additions & 0 deletions test/unit/features/v3/reactivity/readonly.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -525,4 +525,11 @@ describe('reactivity/readonly', () => {
expect(readonlyFoo.x).toBe(1)
expect(`et operation on key "x" failed`).toHaveBeenWarned()
})

test('compatibility with non-extensible objects', () => {
const foo = Object.freeze({ a: 1 })
const bar = readonly(foo)
expect(isReadonly(bar)).toBe(true)
expect(readonly(foo)).toBe(bar)
})
})

0 comments on commit 4a0d88e

Please sign in to comment.