Vue2.x如何实现数据劫持

2020-09-292618
戴国健
web研发

Vue2.x如何实现数据劫持

* 我们在使用vue框架的时候,在创建一个vue实例对象的时候需要传入一个配置对象,其中data节点存放了该组件的数据状态,而我们在使用或者修改data里的数据时候可以直接通过组件本身this去拿到数据进行操作,那么vue框架是如何把data中的数据代理到组件上以及监听到数据的变化呢?

利用Object.defineProperty代理数据

  • Vue构造函数接受一个配置对象options,该options就是我们在创建组件时传入的配置对象。然后在Vue的prototype上定义一个用于初始化函数,其中把options赋值给vue实例上的属性$options,并且调用一个函数初始化状态。

  • 在new Vue的时候将会调用Vue原型链上的初始化方法,并且把options传递到函数中。

  • 图1.png

  • 初始状态函数中接受vue实例对象,并且判断组件上是否存在data节点,如果存在就调用initdata去初始化数据。因为data有可能是函数或者对象,所以利用typeof进行判断,如果是函数就调用并且定义一个变量与vue实例下的_data去接收返回的对象, 如果是对象就直接赋值。

  • 图2.png

  • 遍历data属性,使用Object.defineProperty把vm._data数据代理到vue实例对象下 图3.png 利用递归与Object.definePrototype深度监听data中的数据

  • 因为data中的数据有可能是引用类型的数据,所以使用递归,逐层判断数据类型。

  • 定义一个observe函数,判断data是否是对象类型的数据,注意:这里要排除掉null这种情况.

  • 图片4.png

  • 但因为对象和数组都属于引用类型的数据,所以需要分两种情况。当是数据是一个对象时,仍然是遍历数据中的属性,取到对应的值去使用Object.definePrototype监听数据的变化,但对应的值也有可能是个对象,所以在监听对应的值之前调用observe再次监听该值,并且在设置该属性对应的值的时候,也要调用observe去监听重新赋的值,因为重新赋的值也会可能是一个引用类型数据。

  • 图片5.png

  • 图片6.png

  • 当数据是一个数组时,就无法利用Object.definePrototype去监听了,那么就需要重写那些能够修改元素数组的Array原型链上的方法了

    • 将需要重写的方法枚举出来,例如 push、 pop、shift、unshift
    • 图片7.png
    • 自定义一个原型对象,使用Object.create()去继承原有的数组原型,这是因为一些不改变原数组的方法仍然需要
    • 图片8.png
    • 遍历需要重写的函数名,给自定义的原型对象加上对应的方法,在定义对应方法上,传入的参数个数不一定 ,使用arguments接收参数, 把伪数组转成数组 ,目的是可以调用apply来调用真正的数组方法
    • 利用apply调用实际的数组方法 ,即是Array原型上的方法, 调用该函数是要监听的data中的数组 所以apply中的参数就是监听的数组
    • 图片9.png
    • 判断调用的是数组中的哪个函数,如果数组调用了一些添加元素的方法,把新增的元素组成数组,然后遍历其中元素, 判断新增的元素是不是对象元素,进行深层监听 图片10.png
分享
点赞1
打赏
上一篇:代理工具Fiddler -调试与替换接口状态
下一篇:如何不给自己的 CSS 造坑