Proxy、Reflect
从ECMAScript2015开始,JavaScript新增了Proxy和Reflect对象.通过这两个对象你可以拦截并自定义语言原来的操作行为(例如:属性查找、赋值、枚举、函数调用等).借助这两个对象你可以在JavaScript进行元级别进行编程(元编程).
Proxy
Proxy对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等).
1 | let p = new Proxy(target, handler); |
Proxy和defineProperty,写法上很类似.defineProperty不能对数组进行包装,并且它只有[setter]和[getter]两种对象行为自定义.
1 | let handler = { |

handler
示例
1 | let products = new Proxy({ |
Proxy.revocable(target, handler)
Proxy.revocable(target, handler) 方法可以用来创建一个可撤销的代理对象。
1 | var {proxy, revoke} = Proxy.revocable({}, { |
Reflect
Reflect是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法和Proxy中handler方法一模一样的.都是有十三种handler方法.
Reflect不是构造函数,不能在用new运算符也不能作为函数调用它.Reflect的所有方法和属性都是静态的.
Reflect存在的几个目的:
- 将
Object对象的一些明显属于语言内部的方法(比如Object.defineProperty),放到Reflect对象上。现阶段,某些方法同时在Object和Reflect对象上部署,未来的新方法将只部署在Reflect对象上。也就是说,从Reflect对象上可以拿到语言内部的方法。 - 修改某些
Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。 - 让
Object操作都变成函数行为。某些Object操作是命令式,比如name in obj和delete obj[name],而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为。 Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。
方法
Reflect.apply(target, thisArgument, argumentsList)对一个函数进行调用操作,同时可以传入一个数组作为调用参数。和Function.prototype.apply()功能类似。Reflect.construct(target, argumentsList[, newTarget])对构造函数进行new操作,相当于执行new target(...args)。Reflect.defineProperty(target, propertyKey, attributes)和Object.defineProperty()类似。Reflect.deleteProperty(target, propertyKey)作为函数的delete操作符,相当于执行delete target[name]。Reflect.get(target, propertyKey[, receiver])获取对象身上某个属性的值,类似于target[name]。Reflect.getOwnPropertyDescriptor(target, propertyKey)类似于Object.getOwnPropertyDescriptor()。Reflect.has(target, propertyKey)判断一个对象是否存在某个属性,和in运算符 的功能完全相同。Reflect.ownKeys(target)返回一个包含所有自身属性(不包含继承属性)的数组。(类似于Object.keys(), 但不会受enumerable影响).Reflect.preventExtensions(target)类似于Object.preventExtensions()。返回一个Boolean。Reflect.set(target, propertyKey, value[, receiver])将值分配给属性的函数。返回一个Boolean,如果更新成功,则返回true。Reflect.setPrototypeOf(target, prototype)类似于Object.setPrototypeOf()。

参考
https://tc39.es/ecma262/#sec-reflection
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Meta_programming
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
作者: Fynn
链接: https://fynn90.github.io/2019/09/13/JS_Proxy_and_Reflect/
本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可