共计 2186 个字符,预计需要花费 6 分钟才能阅读完成。
何为元编程?
「编写能扭转语言语法个性或者运行时个性的程序」。换言之,一种语言原本做不到的事件,通过你编程来批改它,使得它能够做到了,这就是元编程。
meta-programming 元编程中的 元 的概念能够了解为 程序 自身。”元编程能让你领有能够扩大程序本身能力
举个例子:
if (a == 1 && a == 2 && a == 3) {console.log("done");
}
怎样才能让这个条件满足,输入 done。依照失常的逻辑是无奈实现的,毕竟一个值不可能同时满足等于 1、2、3
这是就能够用到元编程来扭转这个不可能
let a = {[Symbol.toPrimitive]: ((i) => () => ++i)(0)
}
if (a == 1 && a == 2 && a == 3) {console.log("done");
}
// done
Symbol.toPrimitive
在对象转换为原始值的时候会被调用,初始值为 1,调用一次 +1,就能够满足 a == 1 && a == 2 && a == 3
,同时Symbol.toPrimitive
也能够承受一个参数 hint,hint 的取值为 number、string、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
还有哪些元编程?
proxy
es5 的 Object.defineProperty()办法的 es6 升级版, 用于自定义的对象的行为
let leon = {age: 30}
const validator = {get: function(target, key){
// 若没这个属性返回 37
return key in target ? target[key] : 37;
},
set(target,key,value){if(typeof value!="number" || Number.isNaN(value)){throw new Error("年龄得是数字");
}
}
}
const proxy = new Proxy(leon,validator);
console.log(proxy.name);
// 37
proxy.age = "hi";
// Error: 年龄得是数字
reflect-metadata
你能够通过装璜器来给类增加一些自定义的信息。而后通过反射将这些信息提取进去。当然你也能够通过反射来增加这些信息
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
利用
拓展数组索引拜访
负索引拜访,使array[-N]
与 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
数据劫持
let handlers = Symbol('handlers');
function makeObservable(target) {
// 初始化存储 handler 的数组
target[handlers] = [];
// 存储 handler 函数到数组中以便于将来调用
target.observe = function(handler) {this[handlers].push(handler);
};
// 创立代理以解决更改
return new Proxy(target, {set(target, property, value, receiver) {
// 转发写入操作到指标对象
let success = Reflect.set(...arguments);
// 如果设置属性的时候没有报错
if (success) {
// 调用所有 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
正文完
发表至: javascript
2020-11-30