1、數據代理:一個對象(A)來代理對另一個對象(B)的屬性操作(A一定要包含B)
2、vue中的數據代理:用vm實例對象來代替data 對data中的數據進行操作
(1)vm實例代替data對象操作data對象中的name
<div id="app"> </div> <script type="text/javascript" src="./vue.js"></script> <script type="text/javascript"> const vm = new Vue({ el:'#app', data:{ name:'xxm' } }) console.log(vm.name) //vm對象代替data對象讀取name, vm.name='szz' //vm對象代替data對象操作修改name 的值 console.log(vm) </script>
(2)分析:在控制台中打印輸出vm實例如下
vm實例對象中有_data對象里面存的是屬性,而在外面又有age,name屬性,通過調用vm里面的get()和set()方法就可以代理data對象,對data對象里面的屬性進行操作
3、github上有個大佬仿vue實現了mvvm庫,下面通過mvvm庫來分析vue源碼中的數據代理
地址:https://github.com/DMQ/mvvm
<script type="text/javascript" src="./mvvm/mvvm.js"></script> <script type="text/javascript" src="./mvvm/compile.js"></script> <script type="text/javascript" src="./mvvm/observer.js"></script> <script type="text/javascript" src="./mvvm/watcher.js"></script> <script type="text/javascript"> const vm = new MVVM({ el:'#app', data:{ name:'xxm', age:18 } }) console.log(vm.name) //vm對象代替data對象讀取name, vm.name='szz' //vm對象代替data對象操作修改name 的值 console.log(vm)
4、調試:
(1)第一步:在實例vm上添加斷點
(2)第二步:點擊右側 "↓" 調試進入mvvm.js函數庫,進入MVVM函數庫繼續單步調試
(3)第三步:點擊右側“↓”,進入到代理函數
(4)第四步:在加三個斷點(get(), set())如下
(5)第五步:點擊全部執行
(6)第六步:點擊執行 console.log(vm.name) 會跳到mvvm.js函數庫中,調用執行get()方法
(7)第七步:繼續單步調試,會執行下面這一句,然后set監視到屬性,就會執行mvvm.js中的set()方法
5、數據代理主要用到mvvm.js庫
/* 相關於Vue的構造函數 */ function MVVM(options) { // 將選項對象保存到vm this.$options = options; // 將data對象保存到vm和datq變量中 var data = this._data = this.$options.data; //將vm保存在me變量中 var me = this; // 遍歷data中所有屬性 Object.keys(data).forEach(function (key) { // 屬性名: name // 對指定屬性實現代理 me._proxy(key); }); // 對data進行監視 observe(data, this); // 創建一個用來編譯模板的compile對象 this.$compile = new Compile(options.el || document.body, this) } MVVM.prototype = { $watch: function (key, cb, options) { new Watcher(this, key, cb); }, // 對指定屬性實現代理 _proxy: function (key) { // 保存vm var me = this; // 給vm添加指定屬性名的屬性(使用屬性描述) Object.defineProperty(me, key, { configurable: false, // 不能再重新定義 enumerable: true, // 可以枚舉 // 當通過vm.name讀取屬性值時自動調用 get: function proxyGetter() { // 讀取data中對應屬性值返回(實現代理讀操作) return me._data[key]; }, // 當通過vm.name = 'xxx'時自動調用 set: function proxySetter(newVal) { // 將最新的值保存到data中對應的屬性上(實現代理寫操作) me._data[key] = newVal; } }); } };