Proxy代理对象

290 阅读2分钟

在对vue3进行学习时,发现vue3实现双向数据绑定由Object.defineProperty改为了Proxy,所以对Proxy进行了一波初步了解和学习。

什么是Proxy

Proxy是ES6新增的特性之一。

在《你不知道的JavaScript》(下卷)中对Proxy的解释是:Proxy(代理)是一种由你创建的特殊的对象,它”封装“另一个普通对象——或者说挡在这个普通对象的前面。你可以在代理对象上注册特殊的处理函数(也就是trap),代理上执行各种操作的时候会调用这个程序。这些处理函数除了把操作转发给原始目标/被封装对象之外,还有机会执行额外的逻辑。

Proxy实质上是对一个对象的代理,用于监听一个对象的相关操作。

Proxy接受两个参数,分别是需要被代理的对象和捕获器(trap)。

image.png

Proxy捕获器(trap)

在创建Proxy对象时,第二个参数传入的是捕获器集合,其中最基本的捕获器有getset,分别用于监听获取对象值和给对象赋值的操作。

image.png

在get和set中,可以进行自定义操作。在获取值时对其修饰,或者赋值时,做出限制。

image.png

在set方法中,需要注意的是:set应该返回一个布尔值,返回true表示赋值成功。如果set方法返回false,并且分配发生在严格模式代码中,则会引发TypeError。

image.png

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自己。

image.png

众所周知,在vue2中,直接修改对象的属性值并不能监听到改变,只能够使用$set()方法触发双向数据绑定,这是因为Object.defineProperty的设计初衷并不是为了监听拦截一个对象中的属性,而且它实现不了更加丰富的操作,例如对象的添加、删除属性等操作。

综上,ES6新增了Proxy对象,用于监听Object、Function的操作。在对对象的监听方面,Proxy比Object.defineProperty()更加便捷。

总结

proxy是对一个对象的代理,它可以代理对原对象的操作,原对象对属性值的操作都可以监听拦截,并且捕获器也内置了类似一部分Object对象的方法。在监听对象方面,Proxy比Object.defineProperty()更加便捷。