mirror of
https://github.com/alrayyes/wiki.git
synced 2024-11-22 11:36:23 +00:00
93 lines
2.4 KiB
Markdown
93 lines
2.4 KiB
Markdown
---
|
||
date: 2020-10-22
|
||
id: b866160c-ac93-45af-8faf-1fd40f002f77
|
||
title: JavaScript Metaprogramming
|
||
---
|
||
|
||
# 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
|
||
[eval](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval)[^1]:
|
||
|
||
``` javascript
|
||
console.log(eval("5 + 2")); // 7
|
||
```
|
||
|
||
``` javascript
|
||
const obj = {
|
||
hello() {
|
||
console.log("Hello!");
|
||
},
|
||
};
|
||
|
||
// Meta level
|
||
for (const key of Object.keys(obj)) {
|
||
console.log(key);
|
||
}
|
||
```
|
||
|
||
All [Object.\*
|
||
methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#)
|
||
can be considered metaprogramming functionality
|
||
|
||
# Kinds of metaprogramming
|
||
|
||
Reflective metaprogramming means that a program processes itself.
|
||
Kiczales et al[^2]. \[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()](20200826201605-objects.org::*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.)
|
||
|
||
``` javascript
|
||
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](20201022094207-javascript_proxies) were created to fill that
|
||
gap.
|
||
|
||
# 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](http://mitpress.mit.edu/books/art-metaobject-protocol)" by
|
||
Gregor Kiczales, Jim des Rivieres and Daniel G. Bobrow. Book, 1991.
|