- read

Meta-Programming in JavaScript

The Software Line 38

Meta-Programming in JavaScript

Learn how to use meta programming with the Proxy and Reflect APIs.

The Software Line
Level Up Coding
Published in
3 min readSep 26

--

Photo by Jantine Doornbos on Unsplash

Meta-programming is a programming technique in which computer programs have the ability to treat other programs as their data. This means that a program can be designed to read, generate, analyze, or transform other programs and even modify itself while running.

In the JavaScript programming language, the Proxy and Reflect objects allow you to intercept and define custom behavior for fundamental language operations (e.g., property lookup, assignment, enumeration, function invocation, etc.). With the help of these two objects, you are able to program at the meta-level of JavaScript. So, let’s start with the details for both of them.

1. Proxy API

With the Proxy API, we need to define a target JavaScript object and a proxy handler object, which can contain several methods. Then, we need to create an object of the Proxy class with target and proxy handler objects as constructor parameters.

Inside the proxy handler object, we have the implementation of get and set methods (object property read and set operations). So, as you can see after the creation of the proxy object, we have intercepted the access (read) for three object properties and one object property change (set for the specific property.

let target = {
foo: 'Welcome Foo',
bar: 'Welcome Bar, how are you'
};

let proxyHandler = {
get: function(object, property, receiver) {
console.log('Proxy handler - get property');
return (property in object) ? object[property] : `Hello ${property}`;
},
set: function(object, property, value, receiver) {
console.log('Proxy handler - set property');
object[property] = value;
return true;
}
};

// create a object of Proxy class
let proxy = new Proxy(target, proxyHandler);

console.log(proxy.foo);
console.log(proxy.bar);
console.log(proxy.baz);

proxy.baz = 'baz'

console.log(proxy);

// Proxy handler - get property
// Welcome Foo
// Proxy handler - get property
// Welcome Bar, how are you
// Proxy handler - get property
// Hello baz

// Proxy handler - set property
// { foo: 'Welcome Foo', bar: 'Welcome Bar, how are you', baz: 'baz' }

2. Reflect API

The Reflect namespace object contains static methods for invoking JavaScript object internal methods that can be intercepted. The methods are the same as those of proxy handlers. Reflect is not a constructor, and all the properties and methods are static (we have the same situation with the Math namespace object).

In the example below, we have a target object with properties, and we have one property as the symbol. Then, we are using specific methods from Reflect namespace object with the target object as the input parameter.

let object = { a: 1 };
Object.defineProperty(object, "b", { value: 2 });
object[Symbol("c")] = 3;
console.log('object props', Reflect.ownKeys(object));
console.log('object props symbols', Object.getOwnPropertySymbols(object));
console.log(object);

// object props [ 'a', 'b', Symbol(c) ]
// object props symbols [ Symbol(c) ]
// { a: 1, [Symbol(c)]: 3 }

Conclusion

With knowledge about Proxy and Reflect APIs in JavaScript, we can create some very useful mechanisms inside our Web applications. For example, we can track object access at the application level in order to improve the general performance of the application.