写在前面

如果你对Vue发布订阅的响应式实现有一定的了解,那么你一定知道defineProperty

Object.defineProperty(obj, prop, descriptor)

Vue2.x中的响应式实现正是基于defineProperty中的descriptor,通过属性的getter、setter监听来实现的。
同时你应该知道的是,我们在Vue中使用下标的方式直接修改属性的值或者添加一个预先不存在的对象属性是无法做到setter监听的,这是defineProperty的局限性。
而我们在Vue中使用的pushpopshiftunshiftsplice等一系列修改原数组的方法,其实不是原生的数组方法,都是被Vue修改过的,其中加入了响应代码。

defineProperty中的getter、setter

defineProperty的局限性的最大原因是它只能针对单例属性做监听,Vue2.x中对data中的属性做了遍历 + 递归,为每个属性设置了gettersetter

这也就是为什么Vue只能对data中预定义过的属性做出响应的原因。

Proxy中的getter、setter

Proxy可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
也就是说,Proxy的监听是针对一个对象的,那么对这个对象的所有操作会进入监听操作,这就完全可以代理所有属性了。

Proxy中getter、setter说明

  • get接收三个参数: get(target, propKey, receiver)
  • target是被监听对象,在示例代码中表示的是data propKey是属性名,即当前需要获取的属性名 receiver是监听对象,即Proxy实例,在示例代码中表示的是proxy
  • set接收四个参数: get(target, propKey, value, receiver)
    targetpropKeyreceiver三个参数和get中一样 value表示被修改的值,即测试代码中的1

很明显的是,我们使用Proxy时并不需要关心某一个具体的属性,并且Proxy实例上的修改不会影响到被监听对象target中的值(前提是你不主动修改target)。

Q.E.D.


学而不厌 不耻下问