What is metaprogramming?
Write programs that change syntactic or runtime features of the language. In other words, you can program a language to do something it can’t do, which is metaprogramming.
The concept of meta in programming can be understood as the program itself.” Metaprogramming gives you the ability to extend the program itself
Here’s an example:
if (a == 1 && a == 2 && a == 3) {
console.log("done");
}
Copy the code
How do I make this condition so that I can print done. This cannot be done by normal logic. After all, a value cannot be equal to 1, 2, and 3 at the same time
This is where you can use metaprogramming to change the impossible
let a = {
[Symbol.toPrimitive]: ((i) = > () = > ++i)(0)}if (a == 1 && a == 2 && a == 3) {
console.log("done");
}
// done
Copy the code
Symbol. ToPrimitive is called when the object is converted to its original value. The initial value is 1, and a +1 is called to a == 1&&a == 2&&a == 3. Hint can be number, string, or 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
Copy the code
What else is metaprogramming?
proxy
Es6 upgraded version of es5’s object.defineProperty () method, which is used to customize the behavior of objects
let leon = {
age: 30
}
const validator = {
get: function(target, key){
// Return 37 without this attribute
return key in target ? target[key] : 37;
},
set(target,key,value){
if(typeofvalue! ="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 must be a number
Copy the code
reflect-metadata
You can use decorators to add custom information to a class. This information is then 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
Copy the code
application
Extend array index access
Negative index access makes array[-n] the same as 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
Copy the code
The data was hijacked
let handlers = Symbol('handlers');
function makeObservable(target) {
// Initializes an array of handlers
target[handlers] = [];
// Store handler functions in an array for future calls
target.observe = function(handler) {
this[handlers].push(handler);
};
// Create an agent to handle changes
return new Proxy(target, {
set(target, property, value, receiver) {
// Forward write operations to the target object
let success = Reflect.set(... arguments);// If there is no error when setting the property
if (success) {
// Call all handlers
target[handlers].forEach(handler= > handler(property, value));
}
returnsuccess; }}); }let user = {};
user = makeObservable(user);
user.observe((key, value) = > {
console.log(`SET ${key}=${value}`);
});
user.name = "John";
// SET name=John
Copy the code