国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Vue 進階系列(一)之響應式原理及實現

MonoLog / 1233人閱讀

摘要:進階系列一之響應式原理及實現進階系列二之插件原理及實現進階系列三之函數原理及實現什么是響應式表示一個狀態改變之后,如何動態改變整個系統,在實際項目應用場景中即數據如何動態改變。描述符必須是這兩種形式之一,但二者不能共存,不然會出現異常。

(關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導)

Vue進階系列匯總如下,歡迎閱讀,歡迎加高級前端進階群一起學習(文末)。

Vue 進階系列(一)之響應式原理及實現

Vue 進階系列(二)之插件原理及實現

Vue 進階系列(三)之Render函數原理及實現

什么是響應式Reactivity

Reactivity表示一個狀態改變之后,如何動態改變整個系統,在實際項目應用場景中即數據如何動態改變Dom。

需求

現在有一個需求,有a和b兩個變量,要求b一直是a的10倍,怎么做?

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

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

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

將a和b的關系定義在函數內,那么在改變a之后執行這個函數,b的值就會改變。偽代碼如下。

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

所以現在的問題就變成了如何實現onAChanged函數,當a改變之后自動執行onAChanged,請看后續。

結合view層

現在把a、b和view頁面相結合,此時a對應于數據,b對應于頁面。業務場景很簡單,改變數據a之后就改變頁面b。



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

現在建立數據a和頁面b的關系,用函數包裹之后建立以下關系。



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

再次抽象之后如下所示。


    {{ state.a * 10 }}


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

view = render(state)是所有的頁面渲染的高級抽象。這里暫不考慮view = render(state)的實現,因為需要涉及到DOM結構及其實現等一系列技術細節。這邊需要的是onStateChanged的實現。

實現

實現方式是通過Object.defineProperty中的gettersetter方法。具體使用方法參考如下鏈接。

MDN之Object.defineProperty

需要注意的是getset函數是存取描述符,valuewritable函數是數據描述符。描述符必須是這兩種形式之一,但二者不能共存,不然會出現異常。

實例1:實現convert()函數

要求如下:

1、傳入對象obj作為參數

2、使用Object.defineProperty轉換對象的所有屬性

3、轉換后的對象保留原始行為,但在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函數就可以實現onAChangedonStateChanged

實現:

function convert (obj) {

  // 迭代對象的所有屬性
  // 并使用Object.defineProperty()轉換成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
      }
    })
  })
}
實例2:實現Dep

要求如下:

1、創建一個Dep類,包含兩個方法:dependnotify

2、創建一個autorun函數,傳入一個update函數作為參數

3、在update函數中調用dep.depend(),顯式依賴于Dep實例

4、調用dep.notify()觸發update函數重新運行

示例:

const dep = new Dep()

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

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

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

實現代碼如下。

let activeUpdate = null 

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

wrappedUpdate本質是一個閉包,update函數內部可以獲取到activeUpdate變量,同理dep.depend()內部也可以獲取到activeUpdate變量,所以Dep的實現就很簡單了。

實現代碼如下。

class Dep {

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

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

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

結合上面兩部分就是完整實現。

實例3:實現響應式系統

要求如下:

1、結合上述兩個實例,convert()重命名為觀察者observe()

2、observe()轉換對象的屬性使之響應式,對于每個轉換后的屬性,它會被分配一個Dep實例,該實例跟蹤訂閱update函數列表,并在調用setter時觸發它們重新運行

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

示例:

const state = {
  count: 0
}

observe(state)

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

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

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

class Dep {

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

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

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

function observe (obj) {

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

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

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

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

let activeUpdate = null

function autorun (update) {

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

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

Job Done!!!

本文內容參考自VUE作者尤大的付費視頻
交流

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

http://github.com/yygmind/blog

我是木易楊,網易高級前端工程師,跟著我每周重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!

如果你想加群討論每期面試知識點,公眾號回復[加群]即可

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98945.html

相關文章

  • Vue 進階系列(三)Render函數原理實現

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

    geekidentity 評論0 收藏0
  • Vue 進階系列(二)插件原理實現

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

    wuaiqiu 評論0 收藏0
  • 關于Vue2些值得推薦的文章 -- 五、六月份

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

    sutaking 評論0 收藏0
  • 關于Vue2些值得推薦的文章 -- 五、六月份

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

    khs1994 評論0 收藏0

發表評論

0條評論

MonoLog

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<