Vue數據代理的實現流程逐步講解
一,前言
上篇,主要介紹瞭 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. o p t i o n s ,拿到 d a t a 需要 v m . options,拿到 data 需要 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 取值
三,結尾
本篇主要介紹瞭 Vue 數據初始化流程中,Vue 實例上數據代理的實現,核心思路如下:
- 將 data 暴露在 vm._data 實例屬性上
- 利用 Object.defineProperty 將 vm.xxx 操作代理到 vm._data 上
到此這篇關於Vue數據代理的實現流程逐步講解的文章就介紹到這瞭,更多相關Vue數據代理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Vue數組的劫持逐步分析講解
- JavaScript defineProperty如何實現屬性劫持
- 手寫Vue源碼之數據劫持示例詳解
- vue.js數據響應式原理解析
- proxy實現vue3數據雙向綁定原理