为了更好地操作对象新增了 Proxy 和 ReflectES6

Proxy

相当于在目标对象之前加一层“拦截”,可以对外界的访问进行过滤和改写
可以改变一些默认的语言行为,用自己的定义覆盖了语言的原始定义,属于一种“元编程”(meta programming),即对编程语言进行编程

创建

const p = new Proxy(target, handler)

target:被 Proxy 包装的对象(任何类型的对象,包括原生数组、函数,甚至是另一个代理) handler:代理配置,是一个对象,可以拦截对于对象的大多数操作

支持的拦截操作

handler作用
get拦截对象属性的读取
set拦截对象属性的设置
has拦截 propKey in proxy 的操作
deleteProperty拦截 delete proxy[propKey] 的操作
ownKeys拦截 Object.getOwnPropertyNames(proxy)Object.getOwnPropertySymbols(proxy)Object.keys/values/entriesfor...in 循环
getOwnPropertyDescriptor拦截 Object.getOwnPropertyDescriptor(proxy, propKey)Object.keys/values/entriesfor...in 循环
defineProperty拦截 Object.defineProperty(proxy, propKey, propDesc)Object.defineProperties(proxy, propDescs)
getPrototypeOf拦截 Object.getPrototypeOf(proxy)
setPrototypeOf拦截 Object.setPrototypeOf(proxy, proto)
isExtensible拦截 Object.isExtensible(proxy)
preventExtensions拦截 Object.preventExtensions(proxy)
apply拦截 Proxy 实例作为函数调用的操作,如 proxy(...)proxy.call(...)proxy.apply(...)
construct拦截 Proxy 实例作为构造函数调用的操作,如 new proxy(...args)

代理应该在所有地方都完全替代目标对象。目标对象被代理后,任何地方都不应该再引用原来的目标对象,否则很容易混乱

Reflect

是一个内建对象,不是函数(不能使用 new 调用)

为什么要有 Reflect?

  • JS 有广义的对象(object)和狭义的对象(Object),但是有很多用在广义的对象上的方法都放在了狭义的 Object.prototype 原型上了,导致比较混乱。Reflect 将它们抽出来更合理
  • 对象的获取、设置、遍历、判断等方式分布在各种地方,使用 Reflect 可以统一管理
  • 函数式编程,更规范
  • Reflect 操作函数有返回值 true/false,可以方便地用来进行异常判断

作用

  • 将 Object 属于语言内部的一些方法放到 Reflect 上
  • 修改某些 Object 方法的返回结果,使其更合理
  • 让 Object 操作都变成函数行为,Reflect.has(obj, name) 代替 name in obj
  • Proxy 上有的 Reflect 上都有,所以在 Proxy 上修改默认行为时,都可以通过 Reflect 获取到默认行为,
  • 配合 Proxy 使用,执行原生行为

Reflect 支持调用原始的、语言内部的数据操作方法,以得到原始的结果,执行原始的行为

为什么 Proxy 里面用 Reflect?

解决 this 绑定问题

如果在 proxy 里直接返回原始对象的调用,this 会指向原始对象而不是 proxy 本身:

const target = {
    name: 'Alice',
    get greeting() {
        return `Hello, ${this.name}`;
    }
};
 
const proxy = new Proxy(target, {
    get(target, prop, receiver) {
        return target[prop]; // this 指向 target
        
        return Reflect.get(target, prop, receiver); // this 指向 proxy
    }
});

与原生行为保持一致

当只想拦截某个操作、但仍然希望保留默认行为时,Reflect 是最佳选择(Reflect 既提供了原生行为的方法,又与 Proxy 的方法和入参保持了一致)