# 什么叫元编程
从ECMAScript 2015 开始,JavaScript 获得了 Proxy 和 Reflect 对象的支持,允许你拦截并定义基本语言操作的自定义行为(例如,属性查找,赋值,枚举,函数调用等)。借助这两个对象,你可以在 JavaScript 元级别进行编程。
# 代理
在 ECMAScript 6 中引入的 Proxy 对象可以拦截某些操作并实现自定义行为。例如获取一个对象上的属性
全部方法查看 -MD
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
# 反射
Reflect 是一个内置对象,它提供了可拦截 JavaScript 操作的方法。该方法和代理句柄类似,但 Reflect 方法并不是一个函数对象。
以 Reflect.has() 为例,你可以将 in 运算符作为函数:
全部方法查看 -MD
Reflect.has(Object, 'assign') //true
# 更好的apply 函数
在 ES5 中,我们通常使用 Function.prototype.apply() 方法调用一个具有给定 this 值和 arguments 数组(或类数组对象)的函数
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
使用 Reflect.apply,这变得不那么冗长和容易理解:
Reflect.apply(Math.floor, undefined, [1.75]); // 1
Reflect.apply(RegExp.prototype.exec, /ab/, ['confabulation']).index; //4
Reflect.apply(''.charAt, 'ponies', [3]); // 'i'
# 实现 a==1 && a==2 && a==3
let a = {
[Symbol.toPrimitive]: ((i) => () => ++i)(0)
};
if (a == 1 && a == 2 && a == 3) {
console.log('元编程')
}
重写valueOf/toString
let b = {
val: 1,
valueOf() {
return this.val++
}
}
if (b == 1 && b == 2 && b == 3) {
console.log('重写valueOf/toString ')
}
# 实现JS 负索引
const negativeArray = (els) =>
new Proxy(els, {
get: (target, propKey, receiver) =>
Reflect.get(
target,
+propKey < 0 ? String(target.length + +propKey) : propKey,
receiver
),
});
const unicorn = negativeArray(['我', '是', 'Ao', 'Tu']);
console.log(unicorn[-1]);