写点什么

【Vue2.x 源码学习】第六篇 - 数据代理的实现

用户头像
Brave
关注
发布于: 2021 年 06 月 06 日
【Vue2.x 源码学习】第六篇 -  数据代理的实现

一,前言

上篇,主要介绍了 Vue 数据初始化流程中,数组类型的数据劫持是如何实现的,核心思路如下;


  • 出于对性能的考虑,Vue 没有对数组采用 Object.defineProperty 进行递归劫持,而是对能够导致原数组变化的 7 个方法进行了拦截和重写,实现了对数组的数据劫持


至此,已经完成了对响应式数据(对象和数组)的劫持(深层劫持)操作

本篇,继续介绍 Vue 数据初始化流程中, Vue 实例上数据代理的实现


二,数据代理的实现

1,Vue 是如何操作数据的


在 Vue 中,是可以在外部直接通过 vm 实例进行数据访问和操作:


let vm = new Vue({  el: '#app',  data() {    return { message: 'Hello Vue', obj: { key: "val" }, arr:[1,2,3]}  }});
console.log(vm.message)console.log(vm.arr.push(4))
复制代码


抛出问题:

vm.message 等价于 $options.data.message,是如何实现的?


2,当前是如何操作数据的

当前代码,外部的 vm 实例只能拿到 vm.$options,拿到 data 需要 vm.$options.data

// src/state.js#initData
function initData(vm) { let data = vm.$options.data; data = isFunction(data) ? data.call(vm) : data; observe(data);
data.message data.arr.push(4); }
复制代码


要想实现 vm.message 和 $options.data.message 等效

相当于将 vm 实例操作代理到 $options.data 上,即实现数据代理

3,数据代理的思路

为了让外部的 vm 实例能够拿到观测后的 data,将处理后的 data 直接挂载到 vm 上

// src/state.js#initData
function initData(vm) { let data = vm.$options.data; data = vm._data = isFunction(data) ? data.call(vm) : data; observe(data);}
复制代码

这样,vm 实例就能够在外部通过 vm._data.message 获取到 data.message


接下来,再做一次代理,将 vm 实例操作(vm.message),代理到 vm._data 上即可

4,数据代理的实现

通过 Object.defineProperty 对 _data 中的数据操作进行劫持

即:vm.message 在 vm 实例上取值时,将它代理到 vm._data 上取值

// src/state.js#initData
function initData(vm) { let data = vm.$options.data; data = vm._data = isFunction(data) ? data.call(vm) : data; observe(data); // 当 vm.message 在 vm 实例上取值时,将它代理到vm._data上去取 for(let key in data){ Proxy(vm, key, '_data') }}
// src/state.js#Proxy
/** * 代理方法 * 当取 vm.key 时,将它代理到 vm._data上去取 * @param {*} vm vm 实例 * @param {*} key 属性名 * @param {*} source 代理目标,这里是vm._data */function Proxy(vm, key, source) { Object.defineProperty(vm, key, { get(){ return vm[source][key] }, set(newValue){ vm[source][key] = newValue; } })}
复制代码

5,数据代理的测试

let vm = new Vue({  el: '#app',  data() {    return { message: 'Hello Vue', obj: { key: "val" }, arr:[1,2,3]}  }});
console.log(vm)console.log(vm.message)
复制代码


观察打印结果:

获取 vm 实例时,会通过 get 方法将 _data 全部属性打印出来

当前 vm 实例上,包含 data 全部属性及对应的 get、set 方法


这样,就实现了数据代理:

当从 vm 实例取值时,就会被代理到 vm._data 取值


三,结尾


又成功水了一篇,还剩 15 篇


本篇主要介绍了 Vue 数据初始化流程中,Vue 实例上数据代理的实现,核心思路如下:


将 data 暴露在 vm._data 实例属性上

利用 Object.defineProperty 将 vm.xxx 操作代理到 vm._data 上


下一篇,调试数据劫持和代理


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vue2.x 源码学习】第六篇 -  数据代理的实现