8_vue是如何進行數據代理的
在了解了關於js當中的Object.defineProperty()這個方法後,我們繼續對vue當中的數據代理做一個基於現在的解析
建議觀看之前先了解下js當中的Obejct.defineProperty()
了解如何代理
準備工作
- 準備一個容器,供vue實例對象指定
- 在實例對象當中配置供頁面調用的數據(data)
- 測試頁面
<body>
<!-- 準備一個容器 -->
<div class="subject">
<div>昵稱:{{name}}</div>
<div>電話:{{phone}}</div>
</div>
</body>
<script>
new Vue({
el: '.subject',
data: {
name: 'wavesbright',
phone:"134****2557"
}
});
</script>
查看VM
- 通過之前的複習,我們知道,在vm這個實例對象當中
- 配置項data當中的屬性,會掛載到vm上,供頁面調用
- 而鼠標懸停在二者身上,出現了 invoke property getter,說明什麼?
- 說明,vm上的name和phone,是通過defineProperty 添加上去的 === 做了數據代理
和誰做了數據代理?
- 當你訪問 name 或者 phone的時候
- 一定會調用get(getter),這個get 一定會從某個地方,將所需要的值進行 返回
- 什麼地方? data嘛
- 那你要對 name 和 phone 進行修改的時候,那肯定要 調用set嘛
- 如何確定呢?
get和set
確實有,在哪裡呢,往下翻就可以看到
這不就是代理么
驗證兩條線
vm當中的name 與 phone 是 與data進行數據綁定的
get
- 既然綁定了,那當我訪問name變量的時候
- 先調用get
- get 返回 data.name當中配置的value值
驗證過程
很簡單,直接修改data.name的值不就知道了
原圖
修改後
說明是綁定到一起的嘛,但我為什麼不修改 vm.name的值去查看data是否發生改變了呢?
問題引出1
- 我們設計的data當中的屬性,經過vue的一系列操作
- 最終掛載到了vue實例上,實現了數據綁定
- 數據綁定是一個事實,我們現在所做的是驗證這個過程
- 通過修改配置項 data當中的name屬性,頁面當中確實發生了變化
- 但是我現在想驗證的是,我修改 vm.name的值的時候,data如何確定變化
用vm.data查看就能完成了,這不很簡單嘛?是嗎?
開國際玩笑哦,你data在全局定義了嗎?沒有吧?vm當中為什麼也沒有data呢?
set
解決方式1
定義一個全局的data不就行了
驗證一下嘛,修改vue當中的name屬性,data是否會發生變化
確實可以
問題衍生2
那麼又有一個問題,我這個全局data是自己定義的,而正常構建的vue實例對象可不會這麼寫
但事實情況就是,我修改配置項data當中的數據,可以影響頁面,而修改頁面也可以影響data
我辛辛苦苦配置了一個data對象,交給了vm,vm如果不把我這個data存下來,那人家以後要用屬性去那裡取?vm一定會把這個data留下來。
這就說明一個問題,配置項data,一定在 構建完成的這個實例對象vm身上,但是為什麼找不到呢?
因為人家叫 vm._data
這個就不展開了,因為 vm當中的data除了做數據代理,還有數據劫持
我們當下只需要記住一點,vm._data === data
驗證set的過程
這是當前頁面,現在我們要修改name屬性
修改成全大寫
分析過程
- 我們修改了vm.name的值
- 一定調用了 set函數,拿到這個value值
- 並且將這個 value值賦給了vm._data(data)
圖文解析
第一部分
一切的一切都是因為開頭寫了這段代碼
緊隨其後,馬上就給我們創建了一個vue的實例對象
然後,vue開始為vm這個實例對象準備一些東西(屬性)
重點,data來了,完全來自於上方的配置項data
截止到目前來說,沒有數據代理的存在。我們所寫的data,就是單純的進行了一次賦值,然後給了下劃線data(_data)
第二部分
實際上,vue做到這一步已經差不多了,代碼也是可以寫下去的
但是,請問,目前vm身上,有name嗎,沒有
但是我能拿到name的值嗎?可以的,因為我有 _data
一樣可以拿到name和phone的值
因為,vm這個對象身上的所有屬性,在模板上面都能夠直接使用
但是這樣寫,那不是直接崩潰,創建一個變量就需要 _data一次,vue在這裡做了一個很棒的操作
也就是數據代理
第三部分
- vm在自己身上創建了一個變量name
- 什麼方式創建的?defineProperty
- 通過get拿到vm自身上的_data.name的值
- 修改數據的時候通過set,獲取value,然後再將_data當中的屬性進行修改
- 完成了數據代理,雙向綁定
為什麼要將data當中的數據放在vm身上一份呢(_data)
就是為了讓你編碼的時候更方便(不至於每次都是 _data.xxx)
總結
- vue中的數據代理
- 通過vm對象 來 代理 data對象(配置項)中的屬性操作(get/set)
- Vue中數據代理的好處
- 更加方便操作data中的數據(_data.xxx)
- 基本原理
- 通過Object.defineProperty()將data配置項當中的所有屬性配置到vm對象上
- 為每一個添加到vm上的屬性,指定一個get和set函數(getter/setter)
- 在getter/setter內部去操作(讀/寫),data中對應的屬性
展開_data
思考
老師不讓展開是對的
因為如果按照之前的理解,這個符號代表什麼 (…) 代表數據代理
這樣容易引起理解誤區,,這裡實際上並不是數據代理,而是做了一個數據劫持
我希望看到的 _data的展開內容是什麼?是這樣的
實際上並不是
vue的承諾
只要你敢修改data當中的屬性值,我就敢在頁面當中 {{property}}一起發生變化
- 當name的值發生了改變,最終影響到的是誰 === _data.name
- 那麼頁面元素是怎麼同步進行修改的?
- vue是不是必須要知道,name這裡發生了改變,他需要做什麼 === 監聽
- 經歷了一系列變動後,完成了小小的升級,最終達成響應式操作