Proxy 和 Reflect

Proxy 代理 Array 时, push 方法根据 Array.prototype.push 规范读取和设置数组上的属性。

Proxy 对象用来为基础操作(例如:属性查找、赋值、枚举、方法调用等)定义用户自定义行为
handler
包含 traps 的对象。 拥有跟Reflect一样的方法
traps
提供访问属性的途径,与操作系统中的 traps 定义相似。
target
被代理虚拟化的对象,这个对象常常用作代理的存储后端。关于对象不可拓展性和不可修改属性的不变量会被代理拦截。
应用:
  • 监听原始对象的修改(Reflect.get/Reflect.set) // 不能监听到属性的属性修改,跟moz的watch一样
  • ...

可以代理函数,代理对象还可以调用。但是代理对象不能作为一个元素插入 html 文档

不是所有的的对象都可以透明的进行代理, 如Date这个问题在于大多数的内置构建函数都有一个称之为 internal slots(内部插槽) 的实例。无法找到那些内置的插槽,因为调用 proxy.foo 时 foo 中的 this === proxy。这些插槽是与实例相关的属性类的存储。每当一个对象与 this 关联信息的机制不受到代理所控制,你就有了同样的问题。// Number 也不行

handler.get() 不变量:

如果违背了以下的不变量,proxy会抛出 TypeError:
  • 如果要访问的目标属性是不可写以及不可配置的,则返回的值必须与该目标属性的值相同
    // ES6 class 的 prototype 是不可写不可配置的
  • 如果要访问的目标属性没有配置访问方法,即 get 方法是 undefined 的,则返回值必须为 undefined

Reflect 提供 对象(Object) 的一些静态方法。Proxy 的 handler 基于它

1:更加有用的返回值: Reflect 有一些方法和 ES5 中 Object 方法一样的, 比如: Reflect.getOwnPropertyDescriptor 和 Reflect.defineProperty, 不过 Object.defineProperty(obj, name, desc) 执行成功会返回 obj, 以及其它原因导致的错误, Reflect.defineProperty 只会返回false 或者 true 来表示对象的属性是否设置上了;

2:函数操作, 如果要判断一个obj有定义或者继承了属性name, 在ES5中这样判断:name in obj ; 或者删除一个属性 :delete obj[name], 虽然这些很好用, 很简短, 很明确, 但是要使用的时候也要封装成一个类;有了 Reflect, 它帮你封装好了, Reflect.has(obj, name), Reflect.deleteProperty(obj, name);

3:更加可靠的函数式执行方式: Reflect.apply(f, obj, args)

4:可变参数形式的构造函数(…rest 也行)
var obj = Reflect.construct(F, args, newTarget) // a = {}; F.apply(a, args)