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.
Make Objects Non-Configurable
We can make objects non-configurable.
This means that we can’t change the property descriptor of an object.
The property descriptors include the property value, whether the property is writable, or whether it’s configurable.
Configurable means the ability to change the property descriptions of an object.
To disable configurability, we can write:
const obj = {};
Object.defineProperty(obj, 'foo', {
value: 'bar',
writable: false,
configurable: false
});
We defined the obj.foo
property with the Object.defineProperty
method.
The 3rd argument has the property descriptors.
configurable
set to false
lets us disable changing property descriptors.
We also set writable
to false
so that we can’t change the value of the foo
property’s value.
The enumerate
Trap
ES6 proxies was originally going to include the enumerate
trap to lets us change the behavior of the for-in loop.
But it’s removed to simplified proxies.
The Proxy API
There’re 2 ways to create proxies.
One way is to use the Proxy
constructor.
We can write:
const proxy = new Proxy(target, handler)
The Proxy
constructor takes a target
object and the handler
object to let trap the object operations.
Another way is to use the Proxy.revocable
factory function.
We can write:
const {
proxy,
revoke
} = Proxy.revocable(target, handler)
to use it.
The difference is that there’s the revoke
function to let us revoke access to the proxy.
Handler Methods
The handler
object can have various methods to let us control various object operations.
defineProperty(target, propKey, propDesc)
lets us control how properties are defined with Object.defineProperty
.
target
is the target object that the proxy controls.
propKey
has the property key.
propDesc
is an object with property descriptors.
It returns a boolean.
deleteProperty(target, propKey)
lets us control how properties are defined.
They have the same first 2 parameters as defineProperty
.
It lets us control how the delete
operator works.
get(target, propKey, receiver)
lets us control how properties are retrieved.
receiver
is the proxy object.
It returns the property value that we want to return.
getOwnPropertyDescriptor(target, propKey)
lets us control how property descriptors are returned.
We can use it to return it our way.
It controls how Object.getOwnPropertyDescriptor(proxy, propKey)
acts.
getPrototypeOf(target)
returns the prototype of the target
object.
It controls how Object.getPrototypeOf(proxy)
acts.
has(target, propKey)
lets us control how the in
operator acts.
It should return a boolean.
isExtensible(target)
lets us modify the behavior of the Object.isExtensible(proxy)
method.
It should return a boolean.
ownKeys(target)
can change the behavior of several methods.
It returns an array of property keys.
It controls the behavior of Object.getOwnPropertyPropertyNames(proxy)
to return string keys.
Also, it can control the behavior of Object.getOwnPropertyPropertySymbols(proxy)
to return symbol keys.
And, it can control how the Object.keys(proxy)
method behaves.
preventExtensions(target)
lets us change the behavior of Object.preventExtensions(proxy)
.
It returns boolean.
set(target, propKey, value, receiver)
controls how object properties are set.
It also returns a boolean.
setPrototypeOf(target, proto)
lets us change the behavior of the Object.setPrototypeOf(proxy, proto)
method.
Conclusion
We can control many object operations with proxy handler methods.
Object
static methods can also be controlled with proxy handler methods.