什么是 Proxy ?
Proxy 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”,即对编程语言进行编程。
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
语法
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
1  | const proxy = new Proxy(target, handler)  | 
Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。
其中:
new Proxy()表示生成一个Proxy实例。target参数表示所要拦截的目标对象。handler参数也是一个对象,用来定制拦截行为方法。- 同一个拦截器函数,可以设置拦截多个操作。
 
下面是一个拦截读取属性行为的例子。
1  | const proxy = new Proxy({}, {  | 
handler 对象的方法(拦截方法)
详细介绍见阮一峰老师的ES6入门或MDN
下面是 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)。
Proxy 与 Object.defineProperty 优劣对比
分析
- Object.definedProperty 的作用是劫持一个对象的属性,劫持属性的getter和setter方法,在对象的属性发生变化时进行特定的操作。而 Proxy 劫持的是整个对象。
 - Proxy 会返回一个代理对象,我们只需要操作新对象即可,而 
Object.defineProperty只能遍历对象属性直接修改。 - Object.definedProperty 不支持数组,更准确的说是不支持数组的各种API,因为如果仅仅考虑arry[i] = value 这种情况,是可以劫持的,但是这种劫持意义不大。而 Proxy 可以支持数组的各种API。
 - 尽管 Object.defineProperty 有诸多缺陷,但是其兼容性要好于 Proxy.
 
PS: Vue2.x 使用 Object.defineProperty 实现数据双向绑定,V3.0 则使用了 Proxy.
结论
Proxy 的优势如下:
- Proxy 可以直接监听对象而非属性;
 - Proxy 可以直接监听数组的变化;
 - Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
 - Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
 - Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
 
Object.defineProperty 的优势如下:
- 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平,因此 Vue 的作者才声明需要等到下个大版本( 3.0 )才能用 Proxy 重写。
 
参考文章:

