mirror of
https://github.com/alrayyes/wiki.git
synced 2024-11-29 22:46:22 +00:00
93 lines
2.3 KiB
Markdown
93 lines
2.3 KiB
Markdown
|
---
|
|||
|
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.
|