欧美日韩国产一区二区|qovd片|小明个人发布看看|小浪货你夹真紧水又多|老头把我添高潮了A片故|99热久久精品国产一区二区|久久久春色AV

Vue 理解之白話 getter/setter詳解

當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉為 getter/setter 。Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器
以上摘自 深入響應式原理
那么,把這些屬性全部轉為 getter/setter 具體是怎樣一個過程呢?本文不深入具體 , 簡單大致了解其過程,旨在整體把握,理解其主要思路
假設代碼如下:

Vue 理解之白話 getter/setter詳解

data 選項可以接收一個對象或者方法,這里以對象為例(其實最后都會轉為對象)
首先,這個對象的所有鍵值對都會被掛載在 vm._data 上(此外 vm._data 對象上還有個 __ob__ key,暫時可以忽視),這樣我們便能用 vm._data.msg 訪問到數據
但是通常我們是用 vm.msg 這樣訪問數據,如何做到的呢?其實就是做了個代理 , 將 data 鍵值對中的 vm[key] 的訪問都代理到 vm._data[key] 上
Vue 理解之白話 getter/setter詳解

通常 vm._data (下劃線變量)用作內部程序,對外暴露的 API 是 vm.$data , 其實這兩者也是一個東西 , 也是做了個代理,代碼大概這樣:
Vue 理解之白話 getter/setter詳解

簡單理解就是訪問 vm.data.msg 其實就是訪問 vm._data.msg 。如果直接在開發環境對 vm.data = https://www.questions.com.cn/dnjc/xxx這樣的賦值 , 而不是vm.$data.msg = xxx` 這樣的賦值,后者是沒問題的)
至此,我們理解了為什么能用 vm.msg、vm._data.msg 以及 vm.$data.msg 三種方式獲取/改變數據 , 最原始的數據是 vm._data.msg,而另外兩者即代理了 _data 的數據,vm.$data.msg 即為 Vue 向外提供的 API , 一般情況下開發我們直接用 vm.msg 這樣比較多,也方便,如果要獲取整個 data,程序中需要用 this.$data,而不是 this.data
接下來說 getter/setter
【Vue 理解之白話 getter/setter詳解】將 demo 稍微添點東西:
Vue 理解之白話 getter/setter詳解

msg2 是依賴于 msg 的,當 msg 改變的時候,msg2 的值需要自動更新 , msg 的改變可以在 vm._data.msg 的 setter 中監聽到,但是怎么知道 msg2 是依賴于 msg 的呢?
直觀地我們可以想到,遍歷所有 computed 對象的鍵值對,然后進行分析 , 理論上似乎可行,但是我尋思著這可能需要解析 AST 啊,或者正則去匹配,看看是否用到了 this.msg,也可能是 this.$data.msg 啊 , 還可能是 this._data.msg,而且還要遍歷 data 中的所有 key,這看起來也太麻煩了吧 , 而且,如果程序中沒有用到 msg2,那不是多此一舉了?
事實上 , Vue 初始化的時候會對 vm._data 的每個鍵值對設置 getter/setter,大概代碼如下:
Vue 理解之白話 getter/setter詳解

Vue 響應式核心就是 , setter 的時候會收集依賴,getter 的時候會觸發依賴更新
我們還是以上面的 computed msg2 為例,當我們第一次去取值 msg2 時(注意,必須是取值行為,可以是在 template , 也可以是程序中),勢必需要去取值 this.msg,這就會觸發 msg 的 getter,此時我們就可以確定 msg2 依賴于 msg
msg 可以被哪些東西依賴呢?目前看來有三
template 模版中
computed
watch
我們可以打印 vm._watchers 查看,是一個 Watcher 實例數組,直接看實例的 expression 值,其實就是觸發這個表達式的時候 , 會觸發 msg 的 getter
而這個表達式就對應上述的三種情況,因為 msg 改變的時候,這些表達式需要重新求值,所以這些依賴項都要保存起來,所以源碼中定于了這個 Watcher 類
A watcher parses an expression, collects dependencies, and fires callback when the expression value changes. This is used for both the $watch() api and directives.
watcher.deps 數組表示該 watcher 的依賴項 , 值為 Dep 實例,可以理解成和 Watcher 實例的表達式有關的 data 數據 。注意,deps 數組可能是空,對于 template 而言,可以是 template 中不依賴于 data,對于 computed 而言,可以是這個 computed 數據還沒被獲?。ū熱縹葉ㄒ辶?msg2 , 但是程序中沒有用,這時 deps 為空,這表明我如果改變了 msg,但是不需要通知到 msg2,因為 msg2 根本沒用到嘛,但是我在控制臺輸入 vm.msg2,從而觸發了 msg 的 getter,繼而進行了依賴收集,這時 deps 就不為空了 , 這表明我已經使用了 msg2,下次 msg 更新時需要通知到 msg2 進行改變)
而對于 watch 而言,我試了下任何情況下 deps 都不為空,這需要進一步查看源碼確認
deps 數組元素是 Dep 實例,該實例有個 subs 屬性,是 Watcher 實例數組,表示依賴于這個 Dep 的項目
Watcher 和 Dep 比較難理解,可以暫時這樣理解,Dep 和 data 掛鉤,每一個 Dep 實例就對應 data 的一個鍵值對,Watcher 實例則依賴于 Dep,那么有三個情況會依賴 , 也就是以上三種(想想是不是這樣 , 當數據更新的時候,是不是只有這三處需要同時更新,或者同時響應)
總結下:我們會對 data 中所有鍵值對設置 getter/setter,getter 的時候我們會收集依賴(依賴項為上面三項,并不是任何情況下都會收集依賴,比如在鉤子中打印 msg , 這時候就沒依賴,所以源碼中這里還有復雜判斷),setter 的時候我們會將收集的依賴項觸發 , 從而更新數據,理解了這些,就能初步理解 Vue 的響應式原理 。

相關經驗推薦