ES6 中的 Proxy

前言
如果我们想要监视对象中的属性读写,可以使用 ES5 提供的Object.defineProperty()为对象添加属性,就可以捕获到对象中的属性读写的过程,这种方法应用非常广泛,在 vue3.0 之前的版本就是使用Object.defineProperty()实现数据响应来完成数据的双向绑定
在 ES6 中全新设计了一个叫Proxy的类型,Proxy 这个词的原意是代理,用在这里表示由它来"代理"某些操作,可以译为"代理器",Proxy就是专门为对象设置访问代理器的,无论是读还是写都要经过代理,通过Proxy就能轻松监视对象的读写过程
Proxy 的使用
如何使用Proxy监视对象的读写过程呢?定义一个 person 对象,对象当中有一个 name 属性和 height 属性,然后通过new Proxy的方式为 person 创建一个代理对象
Proxy 的构造函数需要 2 个参数,一个是需要代理的目标对象,另一个是代理的处理对象,在这个处理对象中可以通过get()方法监视对象属性的访问,通过set()方法监视对象设置属性的过程
get()方法
get()方法可以接收两个参数,第一个是代理的目标对象,第二个是访问的属性名,分别把它们打印出来
get()方法正常的逻辑应该是判断代理目标对象中是否存在访问的属性名,存在就返回对应的值,不存在就返回 undefined 或者一个默认值
set()方法
set()方法接收三个参数,第一个是代理的目标对象,第二个是要写入的属性名,第三个是要写入的属性值,分别在方法里将这三个参数打印出来并在外边添加一个属性
控制台就会打印出写入的属性和属性值
set()方法正常的逻辑应该是为代理目标设置指定属性,在设置之前先做一些数据校验,例如属性名为 height,那么那么就要判断它的是否是一个数字,不是就抛出错误
我们分别在控制台去修改 height 为字符串和整数看看,修改为字符串会抛出错误,修改整数才会被成功修改
Proxy 对比 Object.defineProperty
相比于 Object.defineProperty,Proxy 更为强大
Proxy 能够监视到更多的对象操作
defineProperty 只能监视属性的读写,而 Proxy 可以监视到更多的对象操作,例如 delete 操作,对对象当中方法的调用......
在 Proxy 对象的处理对象当中添加一个deleteProperty()代理方法,这个方法会在外部在对代理对象进行操作的时候自动执行
这个方法接收两个参数,代理目标对象和所要删除的属性名称,在这方法内部打印一下要删除的属性名称,然后正常执行 delete 操作,之后在外部去进行 delete 操作
通过控制台可以看成功拦截了 delete 操作并且执行了删除操作
这是defineProperty做不到的,除了 delete 以外还有很多其他的对象操作能被监视到:
apply(tagert,obj,args):拦截函数的调用、call和apply操作has(tagert,key):判断对象是否具有某个属性construct(tagert,args):拦截new命令deleteProperty(tagert,key):拦截delete操作defineProperty(tagert,key,desc):拦截Object.defineProperty()操作getOwnPropertyDescriptor(tagert,key):拦截Object.getOwnPropertyDescriptor()getPrototypeOf(tagert):拦截获取对象原型isExtensible(tagert):拦截Object.isExtensible()操作ownKeys(tagert):拦截对象自身属性的读取操作preventExtensions(tagert):拦截Object.preventExtensions()setPrototypeOf(tagert,proto):拦截Object.setPrototypeOf()方法
Proxy 能更好的支持数组对象的监视
以往通过Object.defineProperty监视数组的操作最常见的就是通过重写数组的操作方法了,在 vue.js 里也是使用这种方式通过自定义方法覆盖掉数组原型对象上的 push(),shift()等方法,以此来劫持对应方法调用的过程
那我们如何使用 Proxy 对象来监视数组?先定义一个数组,为这个数组定义一个 Proxy 对象,在这个 Proxy 对象的处理对象上添加set()方法监视数据的写入,将写入的值赋值给目标对象对应的属性名,然后返回一个 true 代表写入成功
现在在外部对数组的写入操作都会被监视到,通过这个 proxy 对象的 push 方法往数组中添加数据,就可以看到数据被写入了并且控制台成功打印了,这就是 proxy 对数组的监视,要是放在 Object.defineProperty 上去实现就很麻烦
Proxy 是以非侵入的方式监视对象的读写
一个定义好的对象,Proxy 不需要对对象本身做任何操作就可以监视到对象内部成员的读写,而 Object.defineProperty 要求必须通过特定的方式单独去定义对象中需要被监视的属性,这需要去做很多额外的操作,可以看看上一篇的https://xie.infoq.cn/article/858f2cb49013b2f82d9d4edef使用 Object.defineProperty 对对象属性的监视操作
版权声明: 本文为 InfoQ 作者【格斗家不爱在外太空沉思】的原创文章。
原文链接:【http://xie.infoq.cn/article/70b2e521a47fae5b2bc38f8a2】。文章转载请联系作者。










评论