Vue 3 Reactivity System Source Code Reading: `markRaw`

肥仔John發表於2021-11-17

Cauz only Object, Array, Map, Set, WeakMap and WeakSet can be acted for in Vue 3 reactivity system. And to value of the type of Object called by Object.isFrozen returns true or with __v_skip unenumerable property of which value is true will can not proxied as well. VNode is one of the folks has a true __v_skip unenumerable property.

And what markRaw does is to make an object to be out of work in reactivity system. And the implementation is straight forward, as VNode does.

export function markRaw<T extends object>(value: T): T {
    Object.defineProperty(value, '__v_skip', {
        configurable: true,
        enumerable: false,
        value
    })
    return value
}

The source code reading is over there, too simple to do analysis, yeah. But what I wanna do is to dig a bit deeper in object.isFrozen. Let's kick start.

Object.isExtensible

By default, Objects (including Array) are extensible. That means they can have new properties added to them. And Object.isExtensible is used to determine whether an object is extensible.

Important Note: calling Object.isExtensible with the target object returns true, that just means it cannot have additional properties but it doesn't matter to neither removing nor updating exist properties.

In ES5, if an argument to Object.isExtensible is not an object(primitive value), then it will raise a TypeError because of there is no non-object coercion. But in ES2015, that turned out to treat the non-object argument as if it was a non-extensible ordinary object, and return false constantly.

And an object can be marked as non-extensible by the following methods

  • Object.preventExtensions
  • Object.seal
  • object.freeze

Let's have some examples

let names = [
    'John',
    'Mary'
]

Object.preventExtensions(names)
names.push('Tim') // raise `TypeError`
names.remove('John') // it works, ['Mary']
names[0] = 'John' // it turns out to ['John']

How about the corresponding Reflect.isExtensible

Reflect.isExtensible takes the same argument and returns the same result as Object.isExtensible does, but it would not coerce non-object value into non-extensible ordinary one, throws an TypeError instead.

More constraints with Object.isSeal

Object.isSeal method determines if an object is sealed. But what is sealed for an object? In addition to what the non-extensible object does, all properties of sealed object are not removable(a.k.a. non-configurable). However, all its properties are writable still.

Show me instance

let John = {
    nationality: 'China',
    province: 'GuangDong',
    city: 'FoShan',
    hobby: 'skateboard'
}

John.likeSmoking = true // raise `TypeError`, cauz I really don't like having cigarette ;)
delete John.hobby // raise `TypeError`, it's boring with no hobby in your spare time.
John.hobby = 'popping dance' // oh, it works :)

At the last, there is no Reflect.isSeal, and Object.isSeal has the catches as Object.isExtensible, but returns true with non-object input always in ES2015 instead.

The most strict folk Object.isFrozen

A frozen object is that guy with non-extensible, all its properties are not removable or writable. Non-writable properties can be defined in two ways. One is defining accessor property with getter component only. The other is defining by Object.defineProperty with writable: true option.

let John = {
    nationality: 'China',
    province: 'GuangDong',
    city: 'FoShan',
    hobby: 'skateboard'
}

John.likeSmoking = true // raise `TypeError`, cauz I really don't like having cigarette ;)
delete John.hobby // raise `TypeError`, it's boring with no hobby in your spare time.
John.hobby = 'popping dance' // raise `TypeError`, oh no! I can not change what I like :(

Finally, there is no Reflect.isSeal neither. But Object.isFrozen has the catches as Object.isExtensible, but returns true with non-object input always in ES2015 instead.

相關文章