Proxy

defineProperty的问题

虽然Object.defineProperty能够劫持对象的属性,但是需要对对象的每一个属性进行遍历劫持;如果对象上有新增的属性,则需要对新增的属性再次进行劫持;如果属性是对象,还需要深度遍历。这也是为什么Vue给对象新增属性需要通过$set的原因,其原理也是通过Object.defineProperty对新增的属性再次进行劫持。
Object.defineProperty除了能够劫持对象的属性,还可以劫持数组;虽然数组没有属性,但是我们可以把数组的索引看成是属性:

 虽然我们监听到了数组中元素的变化,但是和监听对象属性面临着同样的问题,就是新增的元素并不会触发监听事件,除此之外,直接修改数组的length属性也会导致Object.defineProperty的监听失败。

为此,Vue的解决方案是劫持Array.property原型链上的7个函数,我们通过下面的函数简单进行劫持:

Proxy

相较于Object.defineProperty劫持某个属性,Proxy则更彻底,不在局限某个属性,而是直接对整个对象进行代理。

ES6中对Proxy的描述为:Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

Proxy本身是一个构造函数,通过new Proxy生成拦截的实例对象,让外界进行访问;构造函数中的target就是我们需要代理的目标对象,可以是对象或者数组;handlerObject.defineProperty中的descriptor描述符有些类似,也是一个对象,用来定制代理规则。

可以看到Proxy直接代理了target整个对象,并且返回了一个新的对象,通过监听代理对象上属性的变化来获取目标对象属性的变化;而且我们发现Proxy不仅能够监听到属性的增加,还能监听属性的删除,比Object.defineProperty的功能更为强大。

 不管是数组下标或者数组长度的变化,还是通过函数调用,Proxy都能很好的监听到变化;而且除了我们常用的get、set,Proxy更是支持13种拦截操作。

可以看到Proxy相较于Object.defineProperty在语法和功能上都有着明显的优势;而且Object.defineProperty存在的缺陷,Proxy也都很好地解决了。
 
posted on 2021-01-06 08:33  紅葉  阅读(137)  评论(0编辑  收藏  举报