ES6(三)Proxy和Reflect
本文最后更新于:8 个月前
Proxy对象用来设置拦截器,提供对外界访问的过滤和改写的机制。Reflect对象继承和规范了对象操作的API
ES6(三)Proxy和Reflect
一、Proxy代理器
1. 简介
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
1 |
|
target
,代理的对象handler
,配置对象,用来设置拦截程序
Proxy构造函数返回一个代理器实例,通过这个实例可以实现对原对象(即target)的操作,同时可以自定义一些逻辑,在访问时触发。如果直接访问原对象,将不会触发这些自定义逻辑。
2. 拦截器
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(),分别拦截读取、写操作
1 |
|
1 |
|
apply(),拦截Proxy示例作为函数调用的操作
1 |
|
construct(),拦截Proxy实例作为构造函数调用的操作
1 |
|
receiver指向原始的(读)操作所在的那个对象,一般就是Proxy实例
1 |
|
3. Proxy.revocable() 可取消的代理器
Proxy.revocable()
方法返回一个可取消的 Proxy 实例。
1 |
|
一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。
4. Proxy实例的this指向
Proxy实例的this指向handler
配置对象,这会导致一些错误发生:有些原生对象的内部属性,因为只有通过正确的this
才能拿到,如Date对象
1 |
|
解决办法是:在拦截器中绑定this
指向原生对象
1 |
|
二、Reflect
1. 简介
Reflect
是ES6为了操作对象而提供的新API。Reflect
对象的设计目的有这样几个:
- 将
Object
对象的一些明显属于语言内部的方法(比如Object.defineProperty
),放到Reflect
对象上。 - 修改某些
Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
- 让
Object
操作都变成函数行为 Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。这就让Proxy
对象可以方便地调用对应的Reflect
方法,完成默认行为,作为修改行为的基础。
2. 静态方法
Reflect
对象一共有 13 个静态方法。
- Reflect.apply(target, thisArg, args)
- Reflect.construct(target, args),等同于
new target(...args)
- Reflect.get(target, name, receiver)
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name),等同于
delete obj[name]
- Reflect.has(target, name),对应
name in obj
里面的in
运算符 - Reflect.ownKeys(target),用于返回对象的所有属性
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target),用于读取对象的
__proto__
属性 - Reflect.setPrototypeOf(target, prototype)
Reflect.get
方法查找并返回target
对象的name
属性,如果没有该属性,则返回undefined
。
1 |
|
Reflect.set
方法设置target
对象的name
属性等于value
1 |
|
如果get()
和set()
给了receiver
参数,则读取函数的this
绑定receiver
1 |
|