# 什么叫元编程

从ECMAScript 2015 开始,JavaScript 获得了 ProxyReflect 对象的支持,允许你拦截并定义基本语言操作的自定义行为(例如,属性查找,赋值,枚举,函数调用等)。借助这两个对象,你可以在 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]);
更新时间: 11/13/2020, 8:29:46 PM