在对vue3进行学习时,发现vue3实现双向数据绑定由Object.defineProperty改为了Proxy,所以对Proxy进行了一波初步了解和学习。
什么是Proxy
Proxy是ES6新增的特性之一。
在《你不知道的JavaScript》(下卷)中对Proxy的解释是:Proxy(代理)是一种由你创建的特殊的对象,它”封装“另一个普通对象——或者说挡在这个普通对象的前面。你可以在代理对象上注册特殊的处理函数(也就是trap),代理上执行各种操作的时候会调用这个程序。这些处理函数除了把操作转发给原始目标/被封装对象之外,还有机会执行额外的逻辑。
Proxy实质上是对一个对象的代理,用于监听一个对象的相关操作。
Proxy接受两个参数,分别是需要被代理的对象和捕获器(trap)。
Proxy捕获器(trap)
在创建Proxy对象时,第二个参数传入的是捕获器集合,其中最基本的捕获器有get和set,分别用于监听获取对象值和给对象赋值的操作。
在get和set中,可以进行自定义操作。在获取值时对其修饰,或者赋值时,做出限制。
在set方法中,需要注意的是:set应该返回一个布尔值,返回true表示赋值成功。如果set方法返回false,并且分配发生在严格模式代码中,则会引发TypeError。
Proxy除了set和get外,还有11个捕获器,下图是Proxy的所有捕获器及它们的触发条件
| 方法 | 触发条件 |
|---|---|
| handler.getPrototypeOf() | Object.getPrototypeOf() 方法的捕获器 |
| handler.setPrototypeOf() | Object.setPrototypeOf() 方法的捕获器 |
| handler.isExtensible() | Object.isExtensible() 方法的捕获器 |
| handler.preventExtensions() | Object.preventExtensions() 方法的捕获器 |
| handler.getOwnPropertyDescriptor() | Object.getOwnPropertyDescriptor() 方法的捕获器 |
| handler.defineProperty() | Object.defineProperty() 方法的捕获器 |
| handler.has() | in 操作符的捕获器 |
| handler.get() | 读取属性值的捕获器 |
| handler.set() | 设置属性值的捕获器 |
| handler.deleteProperty() | delete操作符的捕获器 |
| handler.ownKeys() | Object.getOwnPropertyNames() 和 Object.getOwnPropertySymboles() 方法的捕获器 |
| handler.apply() | 函数被apply调用的捕获器 |
| handler.construct() | new操作符的捕获器 |
Proxy的this指向
在Proxy对象中,this指向Proxy自己。
众所周知,在vue2中,直接修改对象的属性值并不能监听到改变,只能够使用$set()方法触发双向数据绑定,这是因为Object.defineProperty的设计初衷并不是为了监听拦截一个对象中的属性,而且它实现不了更加丰富的操作,例如对象的添加、删除属性等操作。
综上,ES6新增了Proxy对象,用于监听Object、Function的操作。在对对象的监听方面,Proxy比Object.defineProperty()更加便捷。
总结
proxy是对一个对象的代理,它可以代理对原对象的操作,原对象对属性值的操作都可以监听拦截,并且捕获器也内置了类似一部分Object对象的方法。在监听对象方面,Proxy比Object.defineProperty()更加便捷。