成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

Vue理解之白話getter/setter詳解

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

專注于為中小企業(yè)提供成都網站制作、成都做網站服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)龍?zhí)睹赓M做網站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網行業(yè)人才,有力地推動了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網站建設實現(xiàn)規(guī)模擴充和轉變。

 以上摘自 深入響應式原理

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

假設代碼如下:

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

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

首先,這個對象的所有鍵值對都會被掛載在 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 (下劃線變量)用作內部程序,對外暴露的 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 的,當 msg 改變的時候,msg2 的值需要自動更新,msg 的改變可以在 vm._data.msg 的 setter 中監(jiān)聽到,但是怎么知道 msg2 是依賴于 msg 的呢?

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

事實上,Vue 初始化的時候會對 vm._data 的每個鍵值對設置 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 響應式核心就是,setter 的時候會收集依賴,getter 的時候會觸發(fā)依賴更新

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

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

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

我們可以打印 vm._watchers 查看,是一個 Watcher 實例數(shù)組,直接看實例的 expression 值,其實就是觸發(fā)這個表達式的時候,會觸發(fā) 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 數(shù)組表示該 watcher 的依賴項,值為 Dep 實例,可以理解成和 Watcher 實例的表達式有關的 data 數(shù)據(jù)。注意,deps 數(shù)組可能是空,對于 template 而言,可以是 template 中不依賴于 data,對于 computed 而言,可以是這個 computed 數(shù)據(jù)還沒被獲?。ū热缥叶x了 msg2,但是程序中沒有用,這時 deps 為空,這表明我如果改變了 msg,但是不需要通知到 msg2,因為 msg2 根本沒用到嘛,但是我在控制臺輸入 vm.msg2,從而觸發(fā)了 msg 的 getter,繼而進行了依賴收集,這時 deps 就不為空了,這表明我已經使用了 msg2,下次 msg 更新時需要通知到 msg2 進行改變)

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

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

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

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

以上所述是小編給大家介紹的Vue getter setter詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對創(chuàng)新互聯(lián)網站的支持!

文章題目:Vue理解之白話getter/setter詳解
本文URL:http://jinyejixie.com/article36/igoipg.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供品牌網站制作、關鍵詞優(yōu)化、響應式網站企業(yè)網站制作、網站制作、營銷型網站建設

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

網站托管運營
中宁县| 博白县| 湘乡市| 禄丰县| 虹口区| 阿拉尔市| 芦溪县| 遵义县| 阿鲁科尔沁旗| 白城市| 博爱县| 富锦市| 灵石县| 体育| 留坝县| 灵武市| 蒲城县| 皋兰县| 海南省| 东平县| 靖州| 荆州市| 苏尼特左旗| 高碑店市| 霍林郭勒市| 双柏县| 合肥市| 东方市| 社会| 灌南县| 巨野县| 晴隆县| 花莲市| 沂源县| 潜江市| 贡嘎县| 涿鹿县| 海城市| 海林市| 喀喇沁旗| 南京市|