Proxy和Reflect
一、Proxy代理对象
- 1、概述
Proxy意思是代理器,ES6新增特性。Proxy对象用于创建一个对象的代理,这个代理会进行拦截操作,在对目标对象的访问和修改前都需要通过这层拦截,在拦截中进行需要的操作。 - 2、语法
let proxy = new Proxy(target, handler)
- target:要进行代理的目标对象,可以是任何东西,包括函数。
- handler:代理配置,或者说拦截操作,是带有钩子的对象。其中钩子包括获取或设置target属性的get和set
一个示例:
let target = {}
let proxy = new Proxy(target, {})
proxy.test = 5
console.log(target.test) // 5
console.log(proxy.test) // 5
上述示例创建了一个代理,但是没有任何钩子。此时所有对proxy的操作都直接转发给target,例如设置对象属性和读取属性值。此时,没有设置拦截操作的proxy就是对target的一个透明包装。proxy对象本身没有自己的属性。想要让proxy有意义,就要进行拦截。
Proxy对目标对象支持的拦截操作共13种,包括以下:
- get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy[‘foo’]。
- set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。
- has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
- deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
- ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
- getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
- defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
- preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
- getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
- isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
- setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
- apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
- construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)。
其中最常见的拦截是get和set钩子,即在读写时进行。
二、Reflect
-
1、概述
Reflect是一个内置对象,提供拦截JS操作的方法,可简化的创建Proxy。与多数全局对象不同,Reflect不是一个构造函数,不能通过new运算符调用,不能把它当作函数调用。Reflect所有属性和方法都是静态的,就像Math对象。 -
2、Reflect作用
-
存放Object对象的一些语言内部的方法(如Object.defineProperty)。现在某些内部方法同时在Object和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)进行同种操作,变为函数行为。
-
简化Proxy。只要是Proxy对象的方法就能在Reflect对象上找到对应方法。Proxy对象就可以方便调用对应的Reflect方法,完成默认行为,作为修改行为的基础。