vue面試題(vue2響應式資料基礎)

平平丶淡淡發表於2024-03-18

一、什麼是響應式資料

響應式資料是指當資料發生變化時,相關的檢視或元件會自動更新,保持與資料的同步。這樣的設計使得開發者能夠更方便地管理和更新資料,無需手動操作DOM或顯式地更新檢視。當資料發生變化時,所有使用該資料的地方都會自動更新。

img

二、觀察者模式

  1. 觀察者模式定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。

  2. 在vue中,可以在模板、計算屬性、偵聽器等地方使用定義在data中的資料,可以理解為這三者都觀察著data中對應資料的變化。模板是渲染watcher、計算屬性是計算屬性watcher、偵聽器是使用者watcher。

  3. 在某個屬性發生變化時,需要去通知使用該屬性的所有地方進行更新,所以該屬性需要將所有依賴該屬性的地方提前收集起來。這個收集所有依賴的容器稱為dep,dep有兩個方法:addSub(收集依賴)、notify(派發更新)。addSub用來儲存watcher,notify用來通知watcher更新。

    // 觀察者
    class Watcher {
      constructor(fn) {
        this.getter = fn;
      }
      // 更新函式,用於觸發更新
      update() {
        this.getter();
      }
    }
    
    // 依賴收集器
    class Dep {
      constructor() {
        // 用來儲存 watcher
        this.subs = [];
      }
      // 新增 watcher
      addSub(watcher) {
        this.subs.push(watcher);
      }
      // 屬性更新,通知所有 watcher 執行對應的更新方法
      notify() {
        this.subs.forEach((watcher) => {
          watcher.update();
        });
      }
    }
    
    const watcher1 = new Watcher(() => {
      console.log("更新Dom");
    });
    const watcher2 = new Watcher(() => {
      console.log("更新計算屬性");
    });
    
    const dep = new Dep();
    dep.addSub(watcher1);
    dep.addSub(watcher2);
    // 當屬性變化時,呼叫該屬性的依賴收集器的notify方法,通知所有watcher更新
    dep.notify();
    

    image-20240313150601085

三、如何實現響應式資料

  1. 資料劫持:即在資料物件身上定義一些特殊的行為。在Vue2中,是透過Object.defineProperty方法實現的。這個方法允許我們為物件的屬性定義getter和setter。
  2. 遞迴轉換:如果資料物件是一個複雜的結構(例如,包含其他物件),我們需要遞迴地對其所有屬性進行相同的轉換,以確保無論資料如何巢狀,都能追蹤其變化。
  3. 依賴收集:當屬性被訪問時(透過getter),需要記錄下哪些檢視或元件依賴於這個屬性。通常是透過一個依賴收集器或觀察者模式實現的。每個依賴都會被新增到一個“依賴列表”中。在下一次屬性被更新時,就可以透過“依賴列表”知道,需要通知哪些檢視或元件去更新。
  4. 通知更新:當屬性被修改時(透過setter),我們需要通知所有依賴於這個屬性的檢視或元件進行更新。這可以透過遍歷依賴列表並觸發它們的更新方法來實現。
  5. 最佳化效能:為了最佳化效能,可能需要實現一些額外的功能,如非同步更新佇列和批處理更新。這可以確保多個屬性的變化只觸發一次檢視更新,而不是每次屬性變化都立即更新。
  6. 處理陣列和特殊方法:對於陣列,我們需要特別處理,因為使用Object.defineProperty來對陣列中的每一個元素實現響應式,效能很差,而且無法監聽到陣列長度的變化。所以Vue透過重寫陣列的一些方法來實現對陣列變化的追蹤。
  7. 提供API:需要提供一套API,讓開發者能夠方便地宣告響應式資料、觀察資料變化以及觸發檢視更新。由於新增屬性和刪除屬性無法監控變化。Vue提供了$set$delete來實現資料的響應式。

四、Vue2實現響應式資料

  1. Vue2透過Object.defineProperty進行資料劫持,需要遍歷物件為屬性新增getter和setter,效能很差
  2. 在元件第一次掛載時,會使用某些響應式資料,因此會觸發資料對應的getter方法,就可以在 getter 中進行依賴收集。在後續資料變化時,會觸發setter 方法,就可以在 setter 中通知依賴進行更新
  3. 新增屬性和刪除屬性監測不到。需要使用$set$delete來實現資料的響應式
  4. 由於陣列的元素可能有很多,迴圈遍歷為每一個元素新增getter和setter效能太差,所以Vue2不對基本型別的陣列元素進行響應式處理,而是重寫陣列相關的方法。
  5. 對於ES6中新產生的Map、Set等資料結構不支援

相關文章