Vue中的数据代理

何为数据代理

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

<script>
  // 最基本最简单的数据代理
  // 有两个对象分别是obj1{ x: 100 } 和obj2{ y: 200 } ,
  // 我想通过obj2访问 obj1的 x 属性,且还能通过 obj2 去修改 obj1的x属性
  let obj1 = { x: 100 }
  let obj2 = { y: 200 }

  Object.defineProperty(obj2, 'x', {
    get() {
      return obj1.x
    },
    set(value) {
      obj1.x = value
    }
  })
</script>

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

以上存在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中的数据是怎么代理的呢?我们也用一个例子来说明

<div id="root">
  <p>姓名:{{name}}</p>
  <p>姓别:{{six}}</p>
</div>

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

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

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

 查看 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 复杂麻烦一点了,但是问题也不大,上例子

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

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

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

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

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

找完了之后,我们发现 ,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

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

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

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

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

初始代码

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

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

这就表明了,当我们在修改  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  却是这样的

 

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值