最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue 理解之白話 getter/setter詳解

 更新時間:2019年04月16日 11:14:38   作者:韓子遲  
這篇文章主要介紹了Vue getter setter,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

當(dāng)你把一個普通的 JavaScript 對象傳給 Vue 實例的 data 選項,Vue 將遍歷此對象所有的屬性,并使用 Object.defineProperty 把這些屬性全部轉(zhuǎn)為 getter/setter。Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是為什么 Vue 不支持 IE8 以及更低版本瀏覽器

 以上摘自 深入響應(yīng)式原理

那么,把這些屬性全部轉(zhuǎn)為 getter/setter 具體是怎樣一個過程呢?本文不深入具體,簡單大致了解其過程,旨在整體把握,理解其主要思路

假設(shè)代碼如下:

const vm = new Vue({
 el: '#app',
 data: {
 msg: 'hello world'
 }
})

data 選項可以接收一個對象或者方法,這里以對象為例(其實最后都會轉(zhuǎn)為對象)

首先,這個對象的所有鍵值對都會被掛載在 vm._data 上(此外 vm._data 對象上還有個 __ob__ key,暫時可以忽視),這樣我們便能用 vm._data.msg 訪問到數(shù)據(jù)

但是通常我們是用 vm.msg 這樣訪問數(shù)據(jù),如何做到的呢?其實就是做了個代理,將 data 鍵值對中的 vm[key] 的訪問都代理到 vm._data[key] 上

proxy(vm, `_data`, key)

export function proxy (target: Object, sourceKey: string, key: string) {
 sharedPropertyDefinition.get = function proxyGetter () {
 return this[sourceKey][key]
 }
 sharedPropertyDefinition.set = function proxySetter (val) {
 this[sourceKey][key] = val
 }
 Object.defineProperty(target, key, sharedPropertyDefinition)
}

通常 vm._data (下劃線變量)用作內(nèi)部程序,對外暴露的 API 是 vm.$data,其實這兩者也是一個東西,也是做了個代理,代碼大概這樣:

const dataDef = {}
dataDef.get = function () { return this._data }

Object.defineProperty(Vue.prototype, '$data', dataDef)

if (process.env.NODE_ENV !== 'production') {
 dataDef.set = function () {
 warn(
  'Avoid replacing instance root $data. ' +
  'Use nested data properties instead.',
  this
 )
 }
}

簡單理解就是訪問 vm.data.msg 其實就是訪問 vm._data.msg。如果直接在開發(fā)環(huán)境對 vm.data = xxx這樣的賦值,而不是vm.$data.msg = xxx` 這樣的賦值,后者是沒問題的)

至此,我們理解了為什么能用 vm.msg、vm._data.msg 以及 vm.$data.msg 三種方式獲取/改變數(shù)據(jù),最原始的數(shù)據(jù)是 vm._data.msg,而另外兩者即代理了 _data 的數(shù)據(jù),vm.$data.msg 即為 Vue 向外提供的 API,一般情況下開發(fā)我們直接用 vm.msg 這樣比較多,也方便,如果要獲取整個 data,程序中需要用 this.$data,而不是 this.data

接下來說 getter/setter

將 demo 稍微添點東西:

const vm = new Vue({
 el: '#app',
 data: {
 msg: 'hello world'
 },
 computed: {
 msg2() {
  return this.msg + '123'
 }
 }
})

msg2 是依賴于 msg 的,當(dāng) msg 改變的時候,msg2 的值需要自動更新,msg 的改變可以在 vm._data.msg 的 setter 中監(jiān)聽到,但是怎么知道 msg2 是依賴于 msg 的呢?

直觀地我們可以想到,遍歷所有 computed 對象的鍵值對,然后進(jìn)行分析,理論上似乎可行,但是我尋思著這可能需要解析 AST 啊,或者正則去匹配,看看是否用到了 this.msg,也可能是 this.$data.msg 啊,還可能是 this._data.msg,而且還要遍歷 data 中的所有 key,這看起來也太麻煩了吧,而且,如果程序中沒有用到 msg2,那不是多此一舉了?

事實上,Vue 初始化的時候會對 vm._data 的每個鍵值對設(shè)置 getter/setter,大概代碼如下:

// obj 即為 vm._data
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
 defineReactive(obj, keys[i])
}

Object.defineProperty(obj, key, {
 enumerable: true,
 configurable: true,
 get: function reactiveGetter () {
 const value = getter ? getter.call(obj) : val
 if (Dep.target) {
  dep.depend()
  if (childOb) {
  childOb.dep.depend()
  if (Array.isArray(value)) {
   dependArray(value)
  }
  }
 }
 return value
 },
 set: function reactiveSetter (newVal) {
 const value = getter ? getter.call(obj) : val
 /* eslint-disable no-self-compare */
 if (newVal === value || (newVal !== newVal && value !== value)) {
  return
 }
 /* eslint-enable no-self-compare */
 if (process.env.NODE_ENV !== 'production' && customSetter) {
  customSetter()
 }
 // #7981: for accessor properties without setter
 if (getter && !setter) return
 if (setter) {
  setter.call(obj, newVal)
 } else {
  val = newVal
 }
 childOb = !shallow && observe(newVal)
 dep.notify()
 }
})

Vue 響應(yīng)式核心就是,setter 的時候會收集依賴,getter 的時候會觸發(fā)依賴更新

我們還是以上面的 computed msg2 為例,當(dāng)我們第一次去取值 msg2 時(注意,必須是取值行為,可以是在 template,也可以是程序中),勢必需要去取值 this.msg,這就會觸發(fā) msg 的 getter,此時我們就可以確定 msg2 依賴于 msg

msg 可以被哪些東西依賴呢?目前看來有三

  1. template 模版中
  2. computed
  3. watch

我們可以打印 vm._watchers 查看,是一個 Watcher 實例數(shù)組,直接看實例的 expression 值,其實就是觸發(fā)這個表達(dá)式的時候,會觸發(fā) msg 的 getter

而這個表達(dá)式就對應(yīng)上述的三種情況,因為 msg 改變的時候,這些表達(dá)式需要重新求值,所以這些依賴項都要保存起來,所以源碼中定于了這個 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 數(shù)組表示該 watcher 的依賴項,值為 Dep 實例,可以理解成和 Watcher 實例的表達(dá)式有關(guān)的 data 數(shù)據(jù)。注意,deps 數(shù)組可能是空,對于 template 而言,可以是 template 中不依賴于 data,對于 computed 而言,可以是這個 computed 數(shù)據(jù)還沒被獲?。ū热缥叶x了 msg2,但是程序中沒有用,這時 deps 為空,這表明我如果改變了 msg,但是不需要通知到 msg2,因為 msg2 根本沒用到嘛,但是我在控制臺輸入 vm.msg2,從而觸發(fā)了 msg 的 getter,繼而進(jìn)行了依賴收集,這時 deps 就不為空了,這表明我已經(jīng)使用了 msg2,下次 msg 更新時需要通知到 msg2 進(jìn)行改變)

而對于 watch 而言,我試了下任何情況下 deps 都不為空,這需要進(jìn)一步查看源碼確認(rèn)

deps 數(shù)組元素是 Dep 實例,該實例有個 subs 屬性,是 Watcher 實例數(shù)組,表示依賴于這個 Dep 的項目

Watcher 和 Dep 比較難理解,可以暫時這樣理解,Dep 和 data 掛鉤,每一個 Dep 實例就對應(yīng) data 的一個鍵值對,Watcher 實例則依賴于 Dep,那么有三個情況會依賴,也就是以上三種(想想是不是這樣,當(dāng)數(shù)據(jù)更新的時候,是不是只有這三處需要同時更新,或者同時響應(yīng))

總結(jié)下:我們會對 data 中所有鍵值對設(shè)置 getter/setter,getter 的時候我們會收集依賴(依賴項為上面三項,并不是任何情況下都會收集依賴,比如在鉤子中打印 msg,這時候就沒依賴,所以源碼中這里還有復(fù)雜判斷),setter 的時候我們會將收集的依賴項觸發(fā),從而更新數(shù)據(jù),理解了這些,就能初步理解 Vue 的響應(yīng)式原理

以上所述是小編給大家介紹的Vue getter setter詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • vue3?typescript封裝axios過程示例

    vue3?typescript封裝axios過程示例

    這篇文章主要為大家介紹了vue3?typescript封裝axios過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • vue項目報錯Uncaught runtime errors的解決方案

    vue項目報錯Uncaught runtime errors的解決方案

    使用vue-cli的vue項目,出現(xiàn)編譯錯誤或警告時,在瀏覽器中顯示全屏覆蓋,提示報錯Uncaught runtime errors,本文給大家介紹了vue項目報錯Uncaught runtime errors的解決方案,需要的朋友可以參考下
    2024-01-01
  • 詳解vue 圖片上傳功能

    詳解vue 圖片上傳功能

    這篇文章主要介紹了vue 圖片上傳功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • vue ajax 攔截原理與實現(xiàn)方法示例

    vue ajax 攔截原理與實現(xiàn)方法示例

    這篇文章主要介紹了vue ajax 攔截原理與實現(xiàn)方法,結(jié)合實例形式分析了vue.js基于ajax攔截實現(xiàn)無刷新登錄的相關(guān)原理與操作技巧,需要的朋友可以參考下
    2019-11-11
  • Vue.js報錯Failed to resolve filter問題的解決方法

    Vue.js報錯Failed to resolve filter問題的解決方法

    這篇文章主要介紹了Vue.js報錯Failed to resolve filter問題的解決方法,需要的朋友可以參考下
    2016-05-05
  • 詳解vue嵌套路由-params傳遞參數(shù)

    詳解vue嵌套路由-params傳遞參數(shù)

    本篇文章主要介紹了詳解vue嵌套路由-params傳遞參數(shù),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • 詳解Vue一個案例引發(fā)「內(nèi)容分發(fā)slot」的最全總結(jié)

    詳解Vue一個案例引發(fā)「內(nèi)容分發(fā)slot」的最全總結(jié)

    這篇文章主要介紹了詳解Vue一個案例引發(fā)「內(nèi)容分發(fā)slot」的最全總結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • vue router總結(jié) $router和$route及router與 router與route區(qū)別

    vue router總結(jié) $router和$route及router與 router與route區(qū)別

    這篇文章主要介紹了vue router總結(jié) $router和$route及router與 router與route區(qū)別,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-07-07
  • 關(guān)于vue編譯版本引入的問題的解決

    關(guān)于vue編譯版本引入的問題的解決

    這篇文章主要介紹了關(guān)于vue編譯版本引入的問題的解決,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • vue項目中使用骨架屏的方法

    vue項目中使用骨架屏的方法

    在頁面加載數(shù)據(jù)之前,有一段空白時間,要么用loading加載,要么就用骨架屏,本文主要介紹了vue項目中使用骨架屏的方法,感興趣的可以了解一下
    2021-05-05

最新評論

泽州县| 井研县| 睢宁县| 罗江县| 满城县| 博罗县| 高淳县| 竹山县| 互助| 安泽县| 如皋市| 阜宁县| 西盟| 睢宁县| 青海省| 平陆县| 鄂托克前旗| 丁青县| 井冈山市| 澄城县| 建湖县| 涟源市| 南岸区| 观塘区| 泰顺县| 南召县| 遂川县| 罗源县| 茶陵县| 嘉鱼县| 麻城市| 翼城县| 兴义市| 荥经县| 乌兰察布市| 泰和县| 通江县| 青田县| 南木林县| 项城市| 牟定县|