0


同学刷抖音的间隙,我学会了Vue数据代理与数据劫持的原理

学习Vue有一段时间了,有粉丝问我,Vue的数据代理与数据劫持到底是什么意思呢?这个过程到底发生了什么呢?今天我就来详细解释一下。

一、基础知识

我们先看 Object.defineProperty()的用法:

Object.defineProperty(obj,prop,descriptor)

参数介绍:

  1. obj:目标对象
  2. prop:需要定义的属性或者方法的名字
  3. descriptorprop属性所具有的特性
  4. 可供定义的特性列表:
  5. value :属性的值
  6. writable:若为false,表示属性值不能重写
  7. get:一旦目标属性被访问,则自动调用该方法,并返回该方法的调用结果
  8. set:一旦目标属性被赋值,则自动调用该方法,进行赋值操作
  9. configurable:若为false,则任何尝试删除目标属性,或修改目标属性的
  10. 以下特性:writableconfigurableenumerable的行为均无效
  11. enumerable:若为true,则可以在for **...** in 循环或Object**.**keys()可以枚举出来

二、数据代理

1、含义

通过一个对象,代理对另一个对象的操作,即:读、写操作。

2、原理

每个 **Vue **应用都是通过用 Vue 函数创建一个新的 Vue 实例开始的:

  1. var vm = new Vue({
  2. // 选项options(配置项)
  3. })
  1. // 数据data对象
  2. var data = { a: 1 }
  3. // 该data对象被加入到一个 Vue 实例中
  4. var vm = new Vue({
  5. data: data
  6. })

上面的代码一般写成下面的形式:也就是直接在Vue函数中,传入 **data **配置对象

  1. const vm = new MVVM({
  2. el: "#root",
  3. data: {
  4. a: 1
  5. }
  6. })

**数据代理的实质是: **

  1. 利用 **Object.defineProperty() **方法,给new出来的Vue实例 **vm **,添加和 **data **配置项中一模一样的属性和值。

  2. 为每一个添加到 **vm **上的属性,都指定一个 **getter/setter **

  3. 在 **getter/setter 内部去操作(读/写)data **中对应的属性

我们可以在控制台打印 **vm **,如下图

可以看到,每一个属性,都有一对 get/set getter/setter方法,这是实现响应式变化的关键

数据代理用到的Vue构造函数伪代码如下:

  1. function MVVM(options){
  2. // 将选项对象保存到vm
  3. this.$options = options
  4. // 将data对象保存到 vm和 新定义的data变量中
  5. var data = this._data = this.$options.data
  6. // 将vm保存在me变量
  7. var me = this
  8. // 遍历data中所有属性名
  9. Object.keys(data).forEach(function (key){
  10. // 每次遍历,实现当前属性的代理
  11. me._proxy(key)
  12. })
  13. // 对data进行监视
  14. observe(data,this)
  15. // 创建一个用来编译模板的compile对象,用来解析模板以及模板里的指令
  16. this.$compile = new Compile(options.el || document.body, this)
  17. }
  18. MVVM.prototype = {
  19. $watch:function(key,cb,options){
  20. new Watcher(this,key,cb)
  21. },
  22. // 调用_proxy方法,对指定的属性实现代理
  23. // _proxy方法接收一个参数key,即原data对象中每个可枚举的属性的属性名
  24. _proxy:function(key){
  25. // 将vm保存在me变量
  26. var me = this
  27. // 给vm添加指定属性名的属性
  28. Object.defineProperty(me,key,{
  29. configurable:false, //不能再重新定义该属性
  30. enumerable:true, //可以枚举
  31. // 使用vm.name的形式读取属性值时,自动调用get/getter回调函数
  32. get:function proxyGetter(){
  33. return me._data[key]
  34. },
  35. // 使用vm.name = 'XXX'形式,写操作时,自动调用set/setter回调函数
  36. set:function proxySetter(newValue){
  37. me._data[key] = newValue
  38. }
  39. })
  40. }
  41. }

在 **new **一个 **Vue **实例的时候,会调用上面的构造函数 **MVVM **:

构造函数 **MVVM **会接收到一个选项对象 **options **(也叫配置对象),也就是我们上面说的 **new Vue **里面的选项对象

{
el: "#root",
data: {
a: 1
}
}

接收到 **options **之后,保存在 **this.$options **中。然后将data对象中的属性赋值给 **this._data **,为了实现响应式, **vm **会对自身 **data **(注意,这是 **vm **自己的 data )进行修改,也就是通过Object.defineProperty()给每一个属性添加上 **getter **和 **setter **方法。

表面上,我们是在操作** vm.xxx **,实际上,我们操作的是 **vm._data.xxx **,也就是 **Vue 选项对象中的 data **,这就是数据代理的本质。

vm的_data中,不只是简单的选项对象中的data

尚硅谷的 Vue 全家桶课程讲解的很棒,我这里粘贴了他们的数据代理图示:

3、好处

使用数据代理,之后我们使用 **vm **,访问 **Vue **函数中 **data **的属性时,直接 this.a 就可以了,不需要使用 *this.data.a 。***注意,这里的 this,指向的是 **vm

三、数据劫持

1. 定义

在上面的数据代理讲解中,我们用到了 Object.defineProperty()方法,在每次对属性进行代理时,访问或者设置对象属性值的时候,总要触发 **get **或 **set **函数,返回需要的值或设置相应属性的值,那么,我们可以在触发函数的时候,动一点手脚,做我们自己想做的事情,这就是“数据劫持”操作。

2.vue原理

Vue的数据劫持,实战就是通过Object.defineProperty()方法来劫持对象属性的getter和setter操作,并安装一个监听器,既可以监听对象,又可以监听数组。当数据发生变化时,就发出通知。

Vue 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 **getter **和 setter 方法,在数据变动时发布消息给订阅者,触发相应的监听回调,实现响应式系统。


本文转载自: https://blog.csdn.net/czjl6886/article/details/122521879
版权归原作者 唯一的阿金 所有, 如有侵权,请联系我们删除。

“同学刷抖音的间隙,我学会了Vue数据代理与数据劫持的原理”的评论:

还没有评论