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】。文章转载请联系作者。
评论