成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Vue 進(jìn)階系列(一)之響應(yīng)式原理及實(shí)現(xiàn)

MonoLog / 1236人閱讀

摘要:進(jìn)階系列一之響應(yīng)式原理及實(shí)現(xiàn)進(jìn)階系列二之插件原理及實(shí)現(xiàn)進(jìn)階系列三之函數(shù)原理及實(shí)現(xiàn)什么是響應(yīng)式表示一個(gè)狀態(tài)改變之后,如何動(dòng)態(tài)改變整個(gè)系統(tǒng),在實(shí)際項(xiàng)目應(yīng)用場(chǎng)景中即數(shù)據(jù)如何動(dòng)態(tài)改變。描述符必須是這兩種形式之一,但二者不能共存,不然會(huì)出現(xiàn)異常。

(關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))

Vue進(jìn)階系列匯總?cè)缦拢瑲g迎閱讀,歡迎加高級(jí)前端進(jìn)階群一起學(xué)習(xí)(文末)。

Vue 進(jìn)階系列(一)之響應(yīng)式原理及實(shí)現(xiàn)

Vue 進(jìn)階系列(二)之插件原理及實(shí)現(xiàn)

Vue 進(jìn)階系列(三)之Render函數(shù)原理及實(shí)現(xiàn)

什么是響應(yīng)式Reactivity

Reactivity表示一個(gè)狀態(tài)改變之后,如何動(dòng)態(tài)改變整個(gè)系統(tǒng),在實(shí)際項(xiàng)目應(yīng)用場(chǎng)景中即數(shù)據(jù)如何動(dòng)態(tài)改變Dom。

需求

現(xiàn)在有一個(gè)需求,有a和b兩個(gè)變量,要求b一直是a的10倍,怎么做?

簡(jiǎn)單嘗試1:
let a = 3;
let b = a * 10;
console.log(b); // 30

乍一看好像滿足要求,但此時(shí)b的值是固定的,不管怎么修改a,b并不會(huì)跟著一起改變。也就是說b并沒有和a保持?jǐn)?shù)據(jù)上的同步。只有在a變化之后重新定義b的值,b才會(huì)變化。

a = 4;
console.log(a); // 4
console.log(b); // 30
b = a * 10;
console.log(b); // 40
簡(jiǎn)單嘗試2:

將a和b的關(guān)系定義在函數(shù)內(nèi),那么在改變a之后執(zhí)行這個(gè)函數(shù),b的值就會(huì)改變。偽代碼如下。

onAChanged(() => {
    b = a * 10;
})

所以現(xiàn)在的問題就變成了如何實(shí)現(xiàn)onAChanged函數(shù),當(dāng)a改變之后自動(dòng)執(zhí)行onAChanged,請(qǐng)看后續(xù)。

結(jié)合view層

現(xiàn)在把a(bǔ)、b和view頁面相結(jié)合,此時(shí)a對(duì)應(yīng)于數(shù)據(jù),b對(duì)應(yīng)于頁面。業(yè)務(wù)場(chǎng)景很簡(jiǎn)單,改變數(shù)據(jù)a之后就改變頁面b。



document
    .querySelector(".cell.b")
    .textContent = state.a * 10

現(xiàn)在建立數(shù)據(jù)a和頁面b的關(guān)系,用函數(shù)包裹之后建立以下關(guān)系。



onStateChanged(() => {
    document
        .querySelector(‘.cell.b’)
        .textContent = state.a * 10
})

再次抽象之后如下所示。


    {{ state.a * 10 }}


onStateChanged(() => {
    view = render(state)
})

view = render(state)是所有的頁面渲染的高級(jí)抽象。這里暫不考慮view = render(state)的實(shí)現(xiàn),因?yàn)樾枰婕暗紻OM結(jié)構(gòu)及其實(shí)現(xiàn)等一系列技術(shù)細(xì)節(jié)。這邊需要的是onStateChanged的實(shí)現(xiàn)。

實(shí)現(xiàn)

實(shí)現(xiàn)方式是通過Object.defineProperty中的gettersetter方法。具體使用方法參考如下鏈接。

MDN之Object.defineProperty

需要注意的是getset函數(shù)是存取描述符,valuewritable函數(shù)是數(shù)據(jù)描述符。描述符必須是這兩種形式之一,但二者不能共存,不然會(huì)出現(xiàn)異常。

實(shí)例1:實(shí)現(xiàn)convert()函數(shù)

要求如下:

1、傳入對(duì)象obj作為參數(shù)

2、使用Object.defineProperty轉(zhuǎn)換對(duì)象的所有屬性

3、轉(zhuǎn)換后的對(duì)象保留原始行為,但在get或者set操作中輸出日志

示例:

const obj = { foo: 123 }
convert(obj)


obj.foo // 輸出 getting key "foo": 123
obj.foo = 234 // 輸出 setting key "foo" to 234
obj.foo // 輸出 getting key "foo": 234

在了解Object.definePropertygettersetter的使用方法之后,通過修改getset函數(shù)就可以實(shí)現(xiàn)onAChangedonStateChanged

實(shí)現(xiàn):

function convert (obj) {

  // 迭代對(duì)象的所有屬性
  // 并使用Object.defineProperty()轉(zhuǎn)換成getter/setters
  Object.keys(obj).forEach(key => {
  
    // 保存原始值
    let internalValue = obj[key]
    
    Object.defineProperty(obj, key, {
      get () {
        console.log(`getting key "${key}": ${internalValue}`)
        return internalValue
      },
      set (newValue) {
        console.log(`setting key "${key}" to: ${newValue}`)
        internalValue = newValue
      }
    })
  })
}
實(shí)例2:實(shí)現(xiàn)Dep

要求如下:

1、創(chuàng)建一個(gè)Dep類,包含兩個(gè)方法:dependnotify

2、創(chuàng)建一個(gè)autorun函數(shù),傳入一個(gè)update函數(shù)作為參數(shù)

3、在update函數(shù)中調(diào)用dep.depend(),顯式依賴于Dep實(shí)例

4、調(diào)用dep.notify()觸發(fā)update函數(shù)重新運(yùn)行

示例:

const dep = new Dep()

autorun(() => {
  dep.depend()
  console.log("updated")
})
// 注冊(cè)訂閱者,輸出 updated

dep.notify()
// 通知改變,輸出 updated

首先需要定義autorun函數(shù),接收update函數(shù)作為參數(shù)。因?yàn)檎{(diào)用autorun時(shí)要在Dep中注冊(cè)訂閱者,同時(shí)調(diào)用dep.notify()時(shí)要重新執(zhí)行update函數(shù),所以Dep中必須持有update引用,這里使用變量activeUpdate表示包裹update的函數(shù)。

實(shí)現(xiàn)代碼如下。

let activeUpdate = null 

function autorun (update) {
  const wrappedUpdate = () => {
    activeUpdate = wrappedUpdate    // 引用賦值給activeUpdate
    update()                        // 調(diào)用update,即調(diào)用內(nèi)部的dep.depend
    activeUpdate = null             // 綁定成功之后清除引用
  }
  wrappedUpdate()                   // 調(diào)用
}

wrappedUpdate本質(zhì)是一個(gè)閉包,update函數(shù)內(nèi)部可以獲取到activeUpdate變量,同理dep.depend()內(nèi)部也可以獲取到activeUpdate變量,所以Dep的實(shí)現(xiàn)就很簡(jiǎn)單了。

實(shí)現(xiàn)代碼如下。

class Dep {

  // 初始化
  constructor () {          
    this.subscribers = new Set()
  }

  // 訂閱update函數(shù)列表
  depend () {
    if (activeUpdate) {     
      this.subscribers.add(activeUpdate)
    }
  }

  // 所有update函數(shù)重新運(yùn)行
  notify () {              
    this.subscribers.forEach(sub => sub())
  }
}

結(jié)合上面兩部分就是完整實(shí)現(xiàn)。

實(shí)例3:實(shí)現(xiàn)響應(yīng)式系統(tǒng)

要求如下:

1、結(jié)合上述兩個(gè)實(shí)例,convert()重命名為觀察者observe()

2、observe()轉(zhuǎn)換對(duì)象的屬性使之響應(yīng)式,對(duì)于每個(gè)轉(zhuǎn)換后的屬性,它會(huì)被分配一個(gè)Dep實(shí)例,該實(shí)例跟蹤訂閱update函數(shù)列表,并在調(diào)用setter時(shí)觸發(fā)它們重新運(yùn)行

3、autorun()接收update函數(shù)作為參數(shù),并在update函數(shù)訂閱的屬性發(fā)生變化時(shí)重新運(yùn)行。

示例:

const state = {
  count: 0
}

observe(state)

autorun(() => {
  console.log(state.count)
})
// 輸出 count is: 0

state.count++
// 輸出 count is: 1

結(jié)合實(shí)例1和實(shí)例2之后就可以實(shí)現(xiàn)上述要求,observe中修改obj屬性的同時(shí)分配Dep的實(shí)例,并在get中注冊(cè)訂閱者,在set中通知改變。autorun函數(shù)保存不變。
實(shí)現(xiàn)如下:

class Dep {

  // 初始化
  constructor () {          
    this.subscribers = new Set()
  }

  // 訂閱update函數(shù)列表
  depend () {
    if (activeUpdate) {     
      this.subscribers.add(activeUpdate)
    }
  }

  // 所有update函數(shù)重新運(yùn)行
  notify () {              
    this.subscribers.forEach(sub => sub())
  }
}

function observe (obj) {

  // 迭代對(duì)象的所有屬性
  // 并使用Object.defineProperty()轉(zhuǎn)換成getter/setters
  Object.keys(obj).forEach(key => {
    let internalValue = obj[key]

    // 每個(gè)屬性分配一個(gè)Dep實(shí)例
    const dep = new Dep()

    Object.defineProperty(obj, key, {
    
      // getter負(fù)責(zé)注冊(cè)訂閱者
      get () {
        dep.depend()
        return internalValue
      },

      // setter負(fù)責(zé)通知改變
      set (newVal) {
        const changed = internalValue !== newVal
        internalValue = newVal
        
        // 觸發(fā)后重新計(jì)算
        if (changed) {
          dep.notify()
        }
      }
    })
  })
  return obj
}

let activeUpdate = null

function autorun (update) {

  // 包裹update函數(shù)到"wrappedUpdate"函數(shù)中,
  // "wrappedUpdate"函數(shù)執(zhí)行時(shí)注冊(cè)和注銷自身
  const wrappedUpdate = () => {
    activeUpdate = wrappedUpdate
    update()
    activeUpdate = null
  }
  wrappedUpdate()
}

結(jié)合Vue文檔里的流程圖就更加清晰了。

Job Done!?。?/p>

本文內(nèi)容參考自VUE作者尤大的付費(fèi)視頻
交流

本人Github鏈接如下,歡迎各位Star

http://github.com/yygmind/blog

我是木易楊,網(wǎng)易高級(jí)前端工程師,跟著我每周重點(diǎn)攻克一個(gè)前端面試重難點(diǎn)。接下來讓我?guī)阕哌M(jìn)高級(jí)前端的世界,在進(jìn)階的路上,共勉!

如果你想加群討論每期面試知識(shí)點(diǎn),公眾號(hào)回復(fù)[加群]即可

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98945.html

相關(guān)文章

  • Vue 進(jìn)階系列(三)Render函數(shù)原理實(shí)現(xiàn)

    摘要:進(jìn)階系列一之響應(yīng)式原理及實(shí)現(xiàn)進(jìn)階系列二之插件原理及實(shí)現(xiàn)進(jìn)階系列三之函數(shù)原理及實(shí)現(xiàn)函數(shù)原理根據(jù)第一篇文章介紹的響應(yīng)式原理,如下圖所示。在初始化階段,本質(zhì)上發(fā)生在函數(shù)中,然后通過函數(shù)生成,根據(jù)生成。負(fù)責(zé)收集依賴,清除依賴和通知依賴。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))showImg(https://segmentfa...

    geekidentity 評(píng)論0 收藏0
  • Vue 進(jìn)階系列(二)插件原理實(shí)現(xiàn)

    摘要:示例輸出第一步先不考慮插件,在已有的中是沒有這個(gè)公共方法的,如果要簡(jiǎn)單實(shí)現(xiàn)的話可以通過鉤子函數(shù)來,即在里面驗(yàn)證邏輯。按照插件的開發(fā)流程,應(yīng)該有一個(gè)公開方法,在里面使用全局的方法添加一些組件選項(xiàng),方法包含一個(gè)鉤子函數(shù),在鉤子函數(shù)中驗(yàn)證。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo))showImg(https://segmen...

    wuaiqiu 評(píng)論0 收藏0
  • 關(guān)于Vue2些值得推薦的文章 -- 五、六月份

    摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

    sutaking 評(píng)論0 收藏0
  • 關(guān)于Vue2些值得推薦的文章 -- 五、六月份

    摘要:五六月份推薦集合查看最新的請(qǐng)點(diǎn)擊集前端最近很火的框架資源定時(shí)更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長(zhǎng)安旅。五月漁郎相憶否。小楫輕舟,夢(mèng)入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請(qǐng)::點(diǎn)擊::集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎 Star 一下。 蘇...

    khs1994 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<