Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at how to control JavaScript object operations.
Function Proxy Handlers
We can also add handler methods to the handler
we pass into the Proxy
constructor or Proxy.revocable
method.
apply(target, thisArgument, argumentsList)
lets us change the behavior of the apply
or call
method.
It can also change the behavior of direct calls to a function.
target
is the target object which we want to control.
thisArgument
lets us pass in the value of this
in the function.
argumentsList
lets us pass in a list of arguments.
Invariants of Handler Methods
Handler methods have various invariants enforced on them.
They include the following.
apply(target, thisArgument, argumentsList)
has no invariants enforced on them.
construct(target, argumentsList, newTarget)
must return an object, and not null
or a primitive value.
defineProperty(target, propKey, propDesc)
must not let us add [properties to an object that isn’t extensible.
The target
must have a property must have a non-configurable own property with propKey
if configurable
is false
.
If writable
and configurable
are both false
, then we can’t write a new property to the property.
deleteProperty(target, propKey)
can’t delete non-configurable own properties of the target
.
get(target, propKey, receiver)
must return the property’s value if it has an own, non-writable, and non-configurable data property with name propKey
.
Otherwise, it must return undefined
.
getOwnPropertyDescriptor(target, propKey)
must return either an object or undefined
.
Non-configurable now properties of the target can’t be reported as non-existent.
If the target is non-extensile, then it must report as existing.
It can’t report a non-configurable property as configurable and can’t report a different value for a non-configurable and non-writable property.
getPrototypeOf(target)
must return either an object or null
.
If the target isn’t extensible, then the handler must return the prototype of the target object.
has(target, propKey)
mustn’t hide a non-configurable own property of target
.
If the target is on-extensible than no own property of target
may be hidden.
isExtensible(target)
must return a boolean.
The coerced boolean value must be the same as target.isExtensible
.
ownKeys(target)
must return an object which is treated as array-like and converted to an array.
Each element of the result must either be a string or a symbol.
The result must have the keys of all non-configurable non-inherited properties of target
.
If target
isn’t extensible then the result must only the keys of its own properties.
preventExtensions(target)
returns a boolean.
target.isExtensible()
must return false
after this is called.
set(target, propKey, value, receiver)
should set the property of a writable, configurable property of target
.
If target
already has an own non-configurable property with name propKey
, then a TypeError
should be thrown since the property can’t be set.
setPrototypeOf(target, proto)
‘s returned result is coerced into a boolean.
If the target isn’t extensible, then its prototype can’t be changed.
In this case, target
‘s prototype must be the same as what it is now, or a TypeError
would be thrown.
Conclusion
The proxy handler methods must follow some conditions even though it lets us customize those operations.
This way, the object operations are still predictable.