何为数据代理
数据代理 :通过一个对象去代理对另外一个对象中属性的操作(读/写)
在控制台上去验证一下数据代理的操作
以上存在3个步骤:
Vue中的数据的代理
上面说完了数据代理的基本模式,那么Vue中的数据是怎么代理的呢?我们也用一个例子来说明
姓名:{{name}}
姓别:{{six}}
这是一个最简单的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 数据代理
2、Vue 数据代理的好处
3、基本原理
4、数据劫持小知识
我们说的 _data 就是 将 data 赋值给了 _data ,那么我们肯定希望,看到的 _data 就和 data 是一样的,但是实际上我们看到的 _data 却是这样的
和我们想的并不一样,这里并不是 data 对象,而是另外一个数据代理对象了,这不就是套娃了么,但是,其实这是经过 Vue 特殊处理过的,因为, Vue 承诺过,一旦 data 内部的数据发生改变,页面就会同步变化,那么 Vue 又是怎么监听到 data 数据变化的呢,这个就是我将要说的数据劫持了。