元编程
代理
Proxy
对象允许你拦截某些操作并实现自定义行为。
例如,获取对象上的属性
js
const handler = {
get(target, name) {
return name in target ? target[name] : 42;
},
};
const p = new Proxy({}, handler);
p.a = 1;
console.log(p.a, p.b); // 1, 42
Proxy
对象定义了一个 target
(此处为空对象)和一个 handler
对象,其中实现了 get
陷阱。这里,代理的对象在获取未定义属性时不会返回 undefined
,而是会返回数字 42
。
Proxy
引用页面上提供了更多示例。
术语
处理程序和陷阱
下表总结了可用于 Proxy
对象的可用陷阱。有关详细说明和示例,请参阅 引用页面。
可撤销的 Proxy
Proxy.revocable()
方法用于创建一个可撤销的 Proxy
对象。这意味着可以通过函数 revoke
撤销代理,并关闭代理。
之后,对代理的任何操作都会导致 TypeError
。
js
const revocable = Proxy.revocable(
{},
{
get(target, name) {
return `[[${name}]]`;
},
},
);
const proxy = revocable.proxy;
console.log(proxy.foo); // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // TypeError: Cannot perform 'get' on a proxy that has been revoked
proxy.foo = 1; // TypeError: Cannot perform 'set' on a proxy that has been revoked
delete proxy.foo; // TypeError: Cannot perform 'deleteProperty' on a proxy that has been revoked
console.log(typeof proxy); // "object", typeof doesn't trigger any trap
反射
Reflect
是一个内置对象,它提供可拦截 JavaScript 操作的方法。这些方法与 代理处理程序 的方法相同。
Reflect
不是函数对象。
Reflect
帮助将默认操作从处理程序转发到 target
。
例如,使用 Reflect.has()
,你可以获得 in
运算符 作为函数
js
Reflect.has(Object, "assign"); // true
更好的 apply() 函数
在 Reflect
之前,你通常使用 Function.prototype.apply()
方法来调用一个函数,并使用给定的 this
值和作为数组(或 类数组对象)提供的 arguments
。
js
Function.prototype.apply.call(Math.floor, undefined, [1.75]);
使用 Reflect.apply
,这变得不那么冗长,更容易理解
js
Reflect.apply(Math.floor, undefined, [1.75]);
// 1
Reflect.apply(String.fromCharCode, undefined, [104, 101, 108, 108, 111]);
// "hello"
Reflect.apply(RegExp.prototype.exec, /ab/, ["confabulation"]).index;
// 4
Reflect.apply("".charAt, "ponies", [3]);
// "i"
检查属性定义是否成功
使用 Object.defineProperty
(如果成功则返回一个对象,否则抛出 TypeError
),你需要使用 try...catch
块来捕获定义属性时发生的任何错误。因为 Reflect.defineProperty()
返回一个布尔成功状态,所以你只需在此处使用 if...else
块
js
if (Reflect.defineProperty(target, property, attributes)) {
// success
} else {
// failure
}