元编程
代理
术语
处理器和陷阱
以下表格中总结了Proxy
对象可用的陷阱。详细的解释和例子请看参考页。
处理器 / 陷阱 | 拦截的操作 | 不变式 |
---|---|---|
handler.getPrototypeOf() | Object.getPrototypeOf() Reflect.getPrototypeOf() __proto__ Object.prototype.isPrototypeOf() instanceof |
|
handler.setPrototypeOf() | Object.setPrototypeOf() Reflect.setPrototypeOf() | 如果target 不可扩展,参数prototype 必须与Object.getPrototypeOf(target) 的值相同。 |
handler.isExtensible() | Object.isExtensible() Reflect.isExtensible() | Object.isExtensible(proxy) 必须返回和Object.isExtensible(target) 一样的值。 |
handler.preventExtensions() | Object.preventExtensions() Reflect.preventExtensions() | 如果Object.isExtensible(proxy) 值为false ,那么Object.preventExtensions(proxy) 只可能返回true 。 |
handler.getOwnPropertyDescriptor() | Object.getOwnPropertyDescriptor() Reflect.getOwnPropertyDescriptor() |
|
handler.defineProperty() | Object.defineProperty() Reflect.defineProperty() |
|
handler.has() |
|
|
handler.get() |
|
|
handler.set() |
|
|
handler.deleteProperty() |
| 如果存在一个对应于target 的属性是不可配置的自有属性,那么该属性不能被删除。 |
handler.ownKeys() | Object.getOwnPropertyNames() Object.getOwnPropertySymbols() Object.keys() Reflect.ownKeys() | |
handler.apply() | proxy(..args) Function.prototype.apply() Function.prototype.call() Reflect.apply() | 不存在关于handler.apply 方法的不变式。 |
handler.construct() | new proxy(...args) Reflect.construct() | 返回值必须是一个Object 。 |
可撤销的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 revokedproxy.foo = 1; // TypeError: Cannot perform 'set' on a proxy that has been revokeddelete proxy.foo; // TypeError: Cannot perform 'deleteProperty' on a proxy that has been revokedconsole.log(typeof proxy); // "object", `typeof` 不会触发任何陷阱
反射
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;// 4Reflect.apply("".charAt, "ponies", [3]);// "i"
检查属性定义是否成功
使用Object.defineProperty
,如果成功则返回一个对象,否则抛出一个TypeError
,你可使用try...catch
块来捕获定义属性时发生的任何错误。因为Reflect.defineProperty
返回一个布尔值表示的成功状态,你可以在这里使用if...else
块:
js
if (Reflect.defineProperty(target, property, attributes)) { // success} else { // failure}