1
头图

What is metaprogramming?

Wikipedia:

meta programming (meta programming) is a programming technique in which a computer program written can treat other programs as data.

Means that such a program can write: it can read generation, analysis or other conversion programs, even modify the program runs itself (reflection).

The concept of element in metaprogramming can be understood as the program itself. Metaprogramming focuses on the following points or points:

  • 1. Modify the language structure at runtime. This phenomenon is called reflection programming or reflection;

    • introspection : code inspection yourself;
    • self-modification : the code modifies itself;
    • mediates : the code modifies the default language behavior of affects other codes;
  • 2. Generate code;

One, introspection

The code can self-check, access internal attributes, and get the underlying information of the code!

// 访问对象自身属性
var users = {
    'Tom': 32,
    'Bill': 50,
    'Sam': 65
};

Object.keys(users).forEach(name => {
    const age = users[name];
    console.log(`User ${name} is ${age} years old!`);
});

// 输出结果
User Tom is 32 years old!
User Bill is 50 years old!
User Sam is 65 years old!

introspection is very common in usual business development, which is also a use of meta-programming technology!

Two, self-modification

As the name implies, the code can modify its own attributes or other underlying information!

let a = 1;
if (a == 1 && a == 2 && a == 3) {
    console.log("元编程");
}

The above code cannot meet the conditional output in any case under normal circumstances.

Because it is impossible for a value to be equal to 1, 2, and 3 at the same time; however, it can be achieved using metaprogramming:

// 修改自身
let a = {
    [Symbol.toPrimitive]: ((i) => () => ++i)(0);
}

if (a == 1 && a == 2 && a == 3) {
    console.log("元编程");
}

// 输出 '元编程'

Symbol.toPrimitive is a built-in Symbol value, which exists as a function value attribute of the object;

It will be called when the object is converted to the original value. The initial value is 1, and +1 is called once to satisfy a == 1 && a == 2 && a == 3 ;

The above function is transformed into:

let a = {
    [Symbol.toPrimitive]: (function (i){
        return function (){
            return ++i
        }
    })(0)
}

if (a == 1 && a == 2 && a == 3) {
    console.log("元编程");
}

In the development process, self-modification should be avoided as much as possible. It is conceivable that when a data is being used and the data is modified at the same time, it is easy to cause unexpected errors afterwards!

3. Mediation

Code modifies the default language behavior and affects other codes. The most obvious manifestation is to change the semantics of other objects!

In metaprogramming, the concept of mediation is similar to packaging, capturing, and intercepting.

Object.defineProperty() is a typical mediation application:

var sun = {};
Object.defineProperty(sun, 'rises', {
    value: true,
    configurable: false,
    writable: false,
    enumerable: false
});

console.log('sun rises', sun.rises);
sun.rises = false;
console.log('sun rises', sun.rises);

// 输出
sun rises true
sun rises true

In the above example, a new common object sun , and then Object.defineProperty changed by 060cd3a99a6637: a non-writable rises attribute was defined for it.

Four, Reflect & Proxy

MDN:

Starting from ECMAScript 2015, JavaScript has gained support for Proxy and Reflect objects, allowing you to intercept and define custom behaviors for basic language operations (for example, attribute lookup, assignment, enumeration, function call, etc.). With these two objects, you can program at the JavaScript meta-level.
// Proxy的handler 和 Reflect 对象 13 个方法

.apply()                                                        // 对一个函数进行调用操作, 和 Function.prototype.apply() 功能类似
.construct()                                                // 对构造函数进行 new 操作,相当于执行 new target(...args)
.get()                                                            // 获取对象身上某个属性的值,类似于 target[name]。
.has()                                                            // 判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同
.ownKeys()                                                    // 返回一个包含所有自身属性(不包含继承属性)的数组,类似于 Object.keys()
.set()                                                            // 将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true
.setPrototypeOf()                                        // 设置对象原型的函数. 返回一个 Boolean, 如果更新成功,则返回true。
.defineProperty()                                        // Object.defineProperty() 类似
.deleteProperty()                                        // 作为函数的delete操作符,相当于执行 delete target[name]。
.getOwnPropertyDescriptor()                    //对象中存在该属性,则返回对应的属性描述符,类似于 Object.getOwnPropertyDescriptor()
.getPrototypeOf()                                        // 类似于 Object.getPrototypeOf()。
.isExtensible()                                            // 类似于 Object.isExtensible()
.preventExtensions()                                // 类似于 Object.preventExtensions()。返回一个Boolean。

1、Reflect

Reflect is a built-in object that provides methods to intercept JavaScript operations.

The method is handler 160cd3a99a67ab 160cd3a99a67ac Proxy, but the Reflect method is not a function object, so it cannot be constructed.

Reflect all properties and methods are static (like Math objects);

Take Reflect.has() as an example, compare with in operator to detect whether an object has a specific attribute:

Reflect.has(Object, "assign");     // true
"assign" in Object;                         // true

2、Proxy

Proxy object introduced in ECMAScript 6 can intercept certain operations and implement custom behaviors.

For example, get the attributes on an object:

let handler = {
  get: function(target, name){
    return name in target ? target[name] : 42;
}};

let p = new Proxy({}, handler);
p.a = 1;

console.log(p.a, p.b); // 1, 42

Proxy object defines a target (here an empty object) and a handler object get

The proxy object will not return undefined when getting undefined attributes, but returns 42.

Five, generate code

The most common function 060cd3a99a6923 that uses meta-programming technology to generate code in eval() incoming string as JavaScript code.

let str = "function sayHello(){console.log('hello')}";
eval(str);
sayHello();

// 输出
hello

Six, summary

Metaprogramming is programming when you turn the logic of a program to focus on itself (or its runtime environment), either to investigate its own structure or to modify it.

The main value of is that 160cd3a99a696c extends the ordinary mechanisms of the language to provide additional capabilities.

reference


哇喔WEB
156 声望1.3k 粉丝

欢迎交流学习