Introduction

In programming, there are levels:

  • At the base level (also called: application level), code processes user input.
  • At the meta level, code processes base level code.

Examples

An example of this is eval1:

console.log(eval("5 + 2")); // 7
const obj = {
  hello() {
    console.log("Hello!");
  },
};
 
// Meta level
for (const key of Object.keys(obj)) {
  console.log(key);
}

All Object.* methods can be considered metaprogramming functionality

Kinds of metaprogramming

Reflective metaprogramming means that a program processes itself. Kiczales et al2. [2] distinguish three kinds of reflective metaprogramming:

  • Introspection: you have read-only access to the structure of a program.
  • Self-modification: you can change that structure
  • Intercession: you can define the semantics of some language operations

Introspection

Object.keys() performs introspection

self-modification

The following function moveProperty moves a property from a source to a target. It performs self-modification via the bracket operator for property access, the assignment operator and the delete operator. (In production code, you’d probably use property descriptors for this task.)

function moveProperty(source, propertyName, target) {
  target[propertyName] = source[propertyName];
  delete source[propertyName];
}
 
const obj1 = { prop: "abc" };
const obj2 = {};
moveProperty(obj1, "prop", obj2);
 
console.log(obj1); // {}
console.log(obj2); // { prop: 'abc' }

intercession

ECMAScript 5 doesn’t support intercession. Proxies were created to fill that gap.

Footnotes

Footnotes

  1. Don’t ever use eval. If you think you’re a clever clogs that can work your away around the obvious security issues, then you especially should not use eval.

  2. The Art of the Metaobject Protocol” by Gregor Kiczales, Jim des Rivieres and Daniel G. Bobrow. Book, 1991.