亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Vue 理解之白話 getter/setter詳解

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

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

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

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

假設(shè)代碼如下:

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

data 選項(xiàng)可以接收一個(gè)對(duì)象或者方法,這里以對(duì)象為例(其實(shí)最后都會(huì)轉(zhuǎn)為對(duì)象)

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

但是通常我們是用 vm.msg 這樣訪問數(shù)據(jù),如何做到的呢?其實(shí)就是做了個(gè)代理,將 data 鍵值對(duì)中的 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)部程序,對(duì)外暴露的 API 是 vm.$data,其實(shí)這兩者也是一個(gè)東西,也是做了個(gè)代理,代碼大概這樣:

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
 )
 }
}

簡(jiǎn)單理解就是訪問 vm.data.msg 其實(shí)就是訪問 vm._data.msg。如果直接在開發(fā)環(huán)境對(duì) 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 這樣比較多,也方便,如果要獲取整個(gè) data,程序中需要用 this.$data,而不是 this.data

接下來說 getter/setter

將 demo 稍微添點(diǎn)東西:

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

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

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

事實(shí)上,Vue 初始化的時(shí)候會(huì)對(duì) vm._data 的每個(gè)鍵值對(duì)設(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 的時(shí)候會(huì)收集依賴,getter 的時(shí)候會(huì)觸發(fā)依賴更新

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

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

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

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

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

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

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

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

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

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

相關(guān)文章

  • 詳解如何使用Vue-PDF在應(yīng)用中嵌入PDF文檔

    詳解如何使用Vue-PDF在應(yīng)用中嵌入PDF文檔

    在現(xiàn)代Web應(yīng)用中,PDF文檔的使用非常普遍,因?yàn)樗梢栽诟鞣N設(shè)備和操作系統(tǒng)上保持一致的外觀和格式,本文我們就來探討一下如何在Vue.js應(yīng)用中使用vue-pdf庫(kù)嵌入PDF文檔吧
    2023-08-08
  • vsCode一鍵生成vue模板

    vsCode一鍵生成vue模板

    之前關(guān)于vsCode一鍵生成vue模,最近需要回顧,就順便發(fā)到隨筆上了,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 快速將Vue項(xiàng)目升級(jí)到webpack3的方法步驟

    快速將Vue項(xiàng)目升級(jí)到webpack3的方法步驟

    這篇文章主要給大家介紹了關(guān)于如何快速將Vue項(xiàng)目升級(jí)到webpack3的方法步驟文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • ElementUI時(shí)間選擇器限制選擇范圍disabledData的使用

    ElementUI時(shí)間選擇器限制選擇范圍disabledData的使用

    本文主要介紹了ElementUI時(shí)間選擇器限制選擇范圍disabledData的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • vue中設(shè)置echarts寬度自適應(yīng)的代碼步驟

    vue中設(shè)置echarts寬度自適應(yīng)的代碼步驟

    這篇文章主要介紹了vue中設(shè)置echarts寬度自適應(yīng)的問題及解決方案,常常需要做到echarts圖表的自適應(yīng),一般是根據(jù)頁(yè)面的寬度做對(duì)應(yīng)的適應(yīng),本文記錄一下設(shè)置echarts圖表的自適應(yīng)的步驟,需要的朋友可以參考下
    2022-09-09
  • vue3實(shí)現(xiàn)多個(gè)表格同時(shí)滾動(dòng)并固定表頭

    vue3實(shí)現(xiàn)多個(gè)表格同時(shí)滾動(dòng)并固定表頭

    這篇文章主要給大家介紹了vue3中多個(gè)表格怎么同時(shí)滾動(dòng)并且固定表頭,文中通過代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • vue項(xiàng)目部署自動(dòng)清除緩存方式

    vue項(xiàng)目部署自動(dòng)清除緩存方式

    這篇文章主要介紹了vue項(xiàng)目部署自動(dòng)清除緩存方式,包括清除文件緩存,清除瀏覽器 localStorage 緩存方式,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • vue.js通過路由實(shí)現(xiàn)經(jīng)典的三欄布局實(shí)例代碼

    vue.js通過路由實(shí)現(xiàn)經(jīng)典的三欄布局實(shí)例代碼

    本文通過實(shí)例代碼給大家介紹了vue.js通過路由實(shí)現(xiàn)經(jīng)典的三欄布局,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-07-07
  • 前端預(yù)覽pdf文件流詳細(xì)步驟

    前端預(yù)覽pdf文件流詳細(xì)步驟

    公司最近有這么個(gè)需求,在線預(yù)覽pdf功能,正好有點(diǎn)時(shí)間,稍微整理記錄一下,這篇文章主要給大家介紹了關(guān)于前端預(yù)覽pdf文件流的相關(guān)資料,需要的朋友可以參考下
    2023-09-09
  • vue 的keep-alive緩存功能的實(shí)現(xiàn)

    vue 的keep-alive緩存功能的實(shí)現(xiàn)

    本篇文章主要介紹了vue 的keep-alive緩存功能的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03

最新評(píng)論