Vue中的数据代理

何为数据代理

 数据代理 :通过一个对象去代理对另外一个对象中属性的操作(读/写)

在控制台上去验证一下数据代理的操作

Vue中的数据代理_第1张图片

以上存在3个步骤:

  1. 直接输出obj2对象,发现,除了原本定义的y属性之外,还存在,x属性,和还存在 对 x 属性的 get() 和 set()
  2. 通过 访问obj2 对象的x属性,其实也就是调用了 obj2 内部的 get x 方法,然后返回了 obj1 对象的x属性。 也就是最终是去访问 obj1 对象中的 x 属性,打印出来是 100
  3. 修改 obj2 对象上的 x 属性值之后,再度输出 obj1 ,发现obj1 内部的 x 属性,也变成了修改后的值,这是因为,通过 obj2 修改 x 属性时,其实是调用了 set x 方法,最终是将 新的值,赋值给了 obj1 中的 x 属性

 Vue中的数据的代理

 上面说完了数据代理的基本模式,那么Vue中的数据是怎么代理的呢?我们也用一个例子来说明

姓名:{{name}}

姓别:{{six}}

这是一个最简单的Vue例子,为了方便后续,我使用了变量 来接收这个 Vue 实例,打印一下看看

Vue中的数据代理_第2张图片

 可以看到,Vue 实例中,是必须存在 name 和 six 属性的,但是这两个属性的值却是没有展示出来,就和我们使用  Object.defineProperty()  代理的数据一样。实际上,我们只在 data 中配置了这两个属性的值,那么我们在 通过 vm 这个Vue实例对象  去访问或者修改这两个 data中的属性  的时候,同样也是调用的 getter 和 setter

Vue中的数据代理_第3张图片

 查看 vm 最下面的属性时,我们也确实发现了 读取和改写 这两个属性的 getter 和 setter

那么这样就完了么,显然不是的,知其然,我们更要知其所以然。下面我们就来验证一下, Vue 究竟是怎么通过 数据代理,访问修改 data中的数据的。分为两条线,

getter :其实就是 get(){} 这个函数,简化叫做 getter

验证 getter 的方式其实很简单,以 name 属性为例,页面上展示的数据,不是从 data 取的么,我们只要改变 data.name 的值之后,然后 通过 vm.name  访问属性,看看 vm.name 是否和 data.name  相同就是了

原始值

 修改 data 数据中 的 name 属性 为 hj

 

 事实证明,vm.name === data.name  这就说明了 Vue 确实是通过 vm实例,去代理 data 对象中属性的读取操作

 setter :set (){}

 证明 setter 就要比 证明 getter 复杂麻烦一点了,但是问题也不大,上例子

Vue中的数据代理_第4张图片

 页面上展示的 姓名 ,就是我data中 初始化的数据,我现在在控制台上 通过 vm 改变这个 name 的值,看看会发生什么

 我们能看到,此时 姓名 的值,已经变成我修改之后的值了。根据我们的 推测,应该是 通过 vn.name = 'hj' 修改属性值之后,调用了 vm 实例 中 关于 name 属性  的 set() 方法,从而造成了页面的变化,但是我们需要怎么验证 data.name  也发生了变化呢?

Vue中的数据代理_第5张图片

 在控制台上直接输入 data.name  想看看 name 属性的值是否发生了变化,这显然是行不通的,data 对象根本就找不到。因为我们的data 根本就不是全局随时都能用的变量啊,它只是 Vue 配置对象中的一个属性呀,当然找不到的。

但是我们接着想啊,我们在实例化之后,这个data能放在哪里呢?我们通过 vm.name  访问的时候,vm 是从哪里取的数据呢?这么一想是不是就明白了? 

在实例化的时候,vm 把 data对象,通过别的方式保存下来了,而且还是保存在 vm 自身上的,不然 访问的时候,通过 getter 去哪里 取数据呢?这样想明白之后,我们就在 vm 自身上找找,有没有类似的属性。

Vue中的数据代理_第6张图片

找完了之后,我们发现 ,vm 身上还真有这么个属性,包含了 name 和 six ,但是这个属性不叫 data 而是叫 _data ,而且,这个 _data 身上,还有 关于 name 和 six 的 getter 和 setter 方法 ,这样一看是不是就明白了,vm._data 其实 就是 构建实例时,传入的 data 属性,我们也可以验证一下

let data = {
  name: 'al',
  six: 'man'
}
const vm = new Vue({
  el: '#root',
  data() {
    return data
  }
})

 我们现在不是找不到 data 么,那我们直接将 data 定义在外部,作为一个全局变量来使用,保证哪里都可以访问到。然后在实例化的时候,我们把这个全局的 data 作为参数传递到配置项中,这样,Vue就自动将 data 转化为 _data 挂载到了 vm实例,此时,我们也可以来验证一下

 两个是全等的,所以 vm._data 就是 data 数据,此时还没有出现对 data 的数据代理,只有Vue 的数据收集

但是当我们改变vm._data.name 的值,就是改变 data.name 也就是改变了 vm.name,此时才触发了 数据代理

 接下来,我们就来验证一下 setter 的 过程是如何运行的

数据初始化

 改变 vm._data.name 

查看此时的 vm.name

Vue中的数据代理_第7张图片

 可以看到,修改了 vm._data.name 之后我们可以发现 vm.name 也发生了改变,这就表明,data 中的 name 也是发生改变了的,这就解释了,为什么页面上的 姓名 会发生变化,因为 一旦 data 中的数据发生改变,页面上所有用到该数据的地方都会同步改变

上述这么大一段逻辑,只是为了证明,vm._data === data 且 vm.name 代理的就是 data.name 

 那么setter又是怎么工作的呢?

一句话解释就是,通过 vm.name  来修改name数据之后,看看最终能不能修改data.name

初始代码

 通过 vm.name 修改之后,发现页面上的 姓名 已经发生改变了

Vue中的数据代理_第8张图片

 这时候查看 data 数据,发现,data 中的数据也是改变了

Vue中的数据代理_第9张图片

这就表明了,当我们在修改  vm.name  属性的时候,此时触发了 setter ,通过 数据代理 使得 vm 对象,代理到了 data 对象,通过 vm 操作了 data 对象内部数据  

数据代理流程

1、首先, new Vue()之时,我们传递了 data,在实例化之后,Vue 实例化对象 vm 上存在了一个 _data 属性,且 _data 对象就是 === data 对象,

2、Vue 将 _data 内部的属性,全部取出挂载到了 vm 实例上,具体做法就是,在 vm 上添加同名属性之后,通过 getter 从 _data  内部取出同名属性且返回,之所以要这样做,是为了方便编码,不然每次都要 _data.xxx  确实挺麻烦的,其实就算使用 _data.xxx  也是可以编码的

3、同理,修改了 vm.xxx 属性之后,会通过 setter 同步 映射到 _data  内部的 xxx 属性上,更新属性值,此时,data 内部的 属性也就同步更改了,页面更新

本章总结

1、Vue 数据代理

  •  通过 vm对象  来代理  data对象中属性的操作(读/写)

2、Vue 数据代理的好处

  • 更加方便的操作data中的数据,毕竟_data.xxx 确实挺麻烦的

3、基本原理

  • 通过Object.defineProperty()  把 data 对象内所有属性,全部添加到 vm 对象上
  • 为每一个添加到 vm 对象上的属性,都添加 getter 和 setter
  • 在每个 getter 和 setter 内部去操作(读/写) data对象中相对应的属性

4、数据劫持小知识

我们说的 _data  就是  将 data  赋值给了 _data ,那么我们肯定希望,看到的 _data 就和 data 是一样的,但是实际上我们看到的 _data  却是这样的

 Vue中的数据代理_第10张图片

和我们想的并不一样,这里并不是 data 对象,而是另外一个数据代理对象了,这不就是套娃了么,但是,其实这是经过 Vue  特殊处理过的,因为, Vue 承诺过,一旦 data 内部的数据发生改变,页面就会同步变化,那么 Vue  又是怎么监听到 data  数据变化的呢,这个就是我将要说的数据劫持了。  

你可能感兴趣的:(vue专栏,vue.js,javascript)