Meta programming in Javascript
From ES6, there are Proxy and Reflect classes that allow us to customize the objects at several language levels. For example property retrieval, assignment, iteration, function invocation, ...
Let us start with several samples.
Example 1: Programmable property retrieval
Let's see an example that you want an object whose properties' values are the properties' names. I.e., obj.a = 'a', obj.b = 'b'
, ...
With Proxy and Reflect, we can have the following implementation to accomplish this.
const obj = new Proxy({}, {get(o, propName){return propName}})
obj.a // = 'a'
obj.b // = 'b'
obj.c // = 'c'
Example 2: customize delete operator.
Requirement: print to console when a property is removed.
const obj = new Proxy({}, {deleteProperty(o, propName){console.log(`${propName} is removed`)}})
delete obj.a // print 'a is removed'
delete obj.a // print 'b is removed'
And many other handlers are supported with their associated Reflect's methods, namely:
- apply() / apply()
- construct() / construct()
- defineProperty() / defineProperty()
- deleteProperty() / deleteProperty()
- get() / get()
- getOwnPropertyDescriptor() / getOwnPropertyDescriptor()
- getPrototypeOf() / getPrototypeOf()
- has() / has()
- isExtensible() / isExtensible()
- ownKeys() / ownKeys()
- preventExtensions() / preventExtensions()
- set() / set()
- setPrototypeOf() / setPrototypeOf()
To reproduce the original behavior of the object in the trap handler, call the associated Reflect's method with the same passed in parameters. For example,
new Proxy(obj, {deleteProperty(...params){return Reflex.deleteProperty(...params)}})
There is also Proxy.revocable(), used to enable the proxy to switch off (at most once).