写文章不容易,点个赞呗兄弟
专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧
研究基于 Vue版本 【2.5.17】
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧javascript
写这篇文章,我就是为了记录我对 Data 的一个疑问的探索,很简短函数
data 的数据是怎么能够经过实例直接访问的?学习
第一想法,或许是,遍历逐个复制?this
可是其实并非,这里涉及的一个词,叫 【代理】spa
怎么代理呢?听我慢慢说,抓住逐个疑问,跟着我慢慢探索3d
实例使用 initData 初始化数据,以下代理
function initData(vm) { var data = vm.$options.data; var keys = Object.keys(data); var i = keys.length; data = vm._data = ( typeof data === 'function' ? data.call(vm) : data ) || {}; while (i--) { var key = keys[i]; if (只要不是_和$开头的属性) { proxy(vm, "_data", key); } } }
首先,拿到 data 数据,若是data 是函数,就执行拿到返回值,不然直接拿设置的对象datacode
第二,保存data 数据对象
源码中你能够看到,把 data 保存到实例上了
vm._data = typeof data === 'function' ? data.call(vm) : data
初始化数据,是为了拿到数据,而后放到存到实例上,做为代理总部
接下来,就放大招了,到了【data 代理】 的重点了,看上面的源码最后
会遍历data对象,若是属性名不是 【_ 或者 $】 开头的话,就会被设置代理
至于为何避开那两个开头的属性?
Vue官网也说明了
剩下的其余属性,会被设置代理,如今咱们来看设置代理的那句话
proxy(vm,"_data",key)
proxy 是什么?不要急,等我放上源码
function proxy(target, sourceKey, key) { Object.defineProperty(target, key, { get() { return this[sourceKey][key] }, set(val) { this[sourceKey][key] = val; } }); }
明白吗?经过 Object.defineProperty 设置 get 和 set 函数,来达到代理,移花接木的过程
可能这么看不太直观,我以一个属性为例写清楚点
因而就会设置成这样
下面是给 _data 属性设置响应式的简化代码
这样的做用,有四个
一、能够直接经过 vm 访问到name
简化写法,你看看 React 这个比,访问 state,须要 http://this.state.xxx 写多一层 很麻烦啊,Vue 作了一层代理就很好,可是呢,成本会大一些
二、保证数据统一
若是是开篇想的那样,逐个赋值,数据改变的时候,就要同时维护两份啊,简直是地狱啊。可是 methods 的处理是直接复制到实例上的
三、不影响依赖收集
当访问 【vm.name】,触发代理 【vm.name 设置的get】,就会访问 【vm._data.name】 ,从而触发总部 【vm._data.name 设置的get】,这个get 用来依赖收集。最后彻底不会影响
四、不影响依赖更新
赋值 【vm.name】,触发代理 【vm.name 设置的 set】,就会直接赋值给总部 【vm._data.name】 ,从而触发 【vm._data.name 设置的set 】,这个set,用来依赖更新。最后彻底不会影响