Talking about Meta programming in es6
- 2021-10-11 17:30:51
- OfStack
What is metaprogramming?
"Write programs that change the syntactic or runtime properties of a language." In other words, what a language can't do, you can modify it by programming, so that it can be done, which is metaprogramming.
The concept of meta in meta-programming metaprogramming can be understood as the program itself. "Metaprogramming gives you the ability to extend the program itself
For example:
if (a == 1 && a == 2 && a == 3) {
console.log("done");
}
How can this condition be met and output done? It can't be done according to normal logic. After all, one value can't satisfy equal to 1, 2 and 3 at the same time
It is possible to use metaprogramming to change this impossible
let a = {
[Symbol.toPrimitive]: ((i) => () => ++i)(0)
}
if (a == 1 && a == 2 && a == 3) {
console.log("done");
}
// done
Symbol. toPrimitive will be called when the object is converted to the original value. The initial value is 1. If you call +1 once, you can satisfy a = = 1
&
&
a == 2
&
&
a = = 3. At the same time, Symbol. toPrimitive can also accept one parameter hint, and the values of hint are number, string and default
let obj = {
[Symbol.toPrimitive](hint) {
switch (hint) {
case "number":
return 123;
case "string":
return "str";
case "default":
return "default";
}
}
}
console.log(1-obj); // -122
console.log(1+obj); // 1default
console.log(`${obj}`); // str
What other metaprogramming?
proxy
es6 upgrade of Object. defineProperty () method of es5 for custom object behavior
let leon = {
age: 30
}
const validator = {
get: function(target, key){
// Returns without this property 37
return key in target ? target[key] : 37;
},
set(target,key,value){
if(typeof value!="number" || Number.isNaN(value)){
throw new Error(" Age has to be a number ");
}
}
}
const proxy = new Proxy(leon,validator);
console.log(proxy.name);
// 37
proxy.age = "hi";
// Error: Age has to be a number
reflect-metadata
You can add some custom information to the class through the decorator. Then this information is extracted by reflection. Of course, you can also add this information through reflection
require("reflect-metadata")
class C {
// @Reflect.metadata(metadataKey, metadataValue)
method() {
}
}
Reflect.defineMetadata("name", "jix", C.prototype, "method");
let metadataValue = Reflect.getMetadata("name", C.prototype, "method");
console.log(metadataValue);
// jix
Application
Extended array index access
Negative index access, making array [-N] identical to array [array. length-N]
let array = [1, 2, 3];
array = new Proxy(array, {
get(target, prop, receiver) {
if (prop < 0) {
console.log(prop, 'prop')
prop = +prop + target.length;
}
return Reflect.get(target, prop, receiver);
}
});
console.log(array[-1]); // 3
console.log(array[-2]); // 2
Data hijacking
let handlers = Symbol('handlers');
function makeObservable(target) {
// Initialization storage handler Array of
target[handlers] = [];
// Storage handler Function into an array for future calls
target.observe = function(handler) {
this[handlers].push(handler);
};
// Create an agent to process changes
return new Proxy(target, {
set(target, property, value, receiver) {
// Forward write operation to target object
let success = Reflect.set(...arguments);
// If no error is reported when setting the property
if (success) {
// Call all handler
target[handlers].forEach(handler => handler(property, value));
}
return success;
}
});
}
let user = {};
user = makeObservable(user);
user.observe((key, value) => {
console.log(`SET ${key}=${value}`);
});
user.name = "John";
// SET name=John