面試官:你可以手寫Vue2的響應式原理嗎续捂?

這道題目是面試中相當高頻的一道題目了,但凡你簡歷上有寫:“熟練使用Vue并閱讀過其部分源碼”抡锈,那么這道題目十有八九面試官都會去問你疾忍。

什么?你簡歷上不寫閱讀過源碼床三,那面試官也很有可能會問你是否閱讀過響應式相關的源碼

還是那句歌詞唱的:

掙不脫 逃不過
眉頭解不開的結
命中解不開的劫
image.png

整體流程

作為一個前端的MVVM框架一罩,Vue的基本思路和Angular讥巡、React并無二致熙涤,其核心就在于: 當數據變化時,自動去刷新頁面DOM穷躁,這使得我們能從繁瑣的DOM操作中解放出來四瘫,從而專心地去處理業(yè)務邏輯汉嗽。
這就是Vue的數據雙向綁定(又稱響應式原理)。數據雙向綁定是Vue最獨特的特性之一找蜜。此處我們用官方的一張流程圖來簡要地說明一下Vue響應式系統的整個流程:

image.png

Vue中饼暑,每個組件實例都有相應的watcher實例對象,它會在組件渲染的過程中把屬性記錄為依賴洗做,之后當依賴項的setter被調用時弓叛,會通知watcher重新計算,從而致使它關聯的組件得以更新诚纸。

這是一個典型的觀察者模式撰筷。

關鍵角色

Vue 數據雙向綁定的實現邏輯里,有這樣三個關鍵角色:

  • Observer: 它的作用是給對象的屬性添加gettersetter畦徘,用于依賴收集和派發(fā)更新
  • Dep: 用于收集當前響應式對象的依賴關系,每個響應式對象包括子對象都擁有一個Dep實例(里面subsWatcher實例數組),當數據有變更時,會通過dep.notify()通知各個watcher毕籽。
  • Watcher: 觀察者對象 , 實例分為渲染 watcher (render watcher),計算屬性 watcher (computed watcher),偵聽器watcher(user watcher)三種

Watcher 和 Dep 的關系

為什么要單獨拎出來一小節(jié)專門來說這個問題呢?因為大部分同學只是知道:Vue的響應式原理是通過Object.defineProperty實現的井辆。被Object.defineProperty綁定過的對象关筒,會變成「響應式」化。也就是改變這個對象的時候會觸發(fā)getset事件杯缺。
但是對于里面具體的對象依賴關系并不是很清楚平委,這樣也就給了面試官一種:你只是背了答案,對于響應式的內部實現細節(jié)夺谁,你并不是很清楚的印象廉赔。
關于WatcherDep 的關系這個問題肉微,其實剛開始我也不是很清楚,在查閱了相關資料后蜡塌,才逐漸對里面的具體實現有了清晰的理解碉纳。

image.png

剛接觸Dep這個詞的同學都會比較懵: Dep究竟是用來做什么的呢?我們通過defineReactive方法將data中的數據進行響應式后馏艾,雖然可以監(jiān)聽到數據的變化了劳曹,那我們怎么處理通知視圖就更新呢?
Dep就是幫我們依賴管理的琅摩。
如上圖所示:一個屬性可能有多個依賴铁孵,每個響應式數據都有一個Dep來管理它的依賴。

一段話總結原理

上面說了那么多房资,下面我總結一下Vue響應式的核心設計思路:
當創(chuàng)建Vue實例時,vue會遍歷data選項的屬性,利用Object.defineProperty為屬性添加gettersetter對數據的讀取進行劫持(getter用來依賴收集,setter用來派發(fā)更新),并且在內部追蹤依賴,在屬性被訪問和修改時通知變化蜕劝。
每個組件實例會有相應的watcher實例,會在組件渲染的過程中記錄依賴的所有數據屬性(進行依賴收集,還有computed watcher,user watcher實例),之后依賴項被改動時,setter方法會通知依賴與此data的watcher實例重新計算(派發(fā)更新),從而使它關聯的組件重新渲染。
到這里轰异,我們已經了解了“套路”岖沛,下面讓我們用偽代碼來實現一下Vue的響應式吧!

核心實現

/**
 * @name Vue數據雙向綁定(響應式系統)的實現原理
 */

// observe方法遍歷并包裝對象屬性
function observe(target) {
  // 若target是一個對象搭独,則遍歷它
  if (target && typeof target === "Object") {
    Object.keys(target).forEach((key) => {
      // defineReactive方法會給目標屬性裝上“監(jiān)聽器”
      defineReactive(target, key, target[key]);
    });
  }
}
// 定義defineReactive方法
function defineReactive(target, key, val) {
  const dep = new Dep();
  // 屬性值也可能是object類型婴削,這種情況下需要調用observe進行遞歸遍歷
  observe(val);
  // 為當前屬性安裝監(jiān)聽器
  Object.defineProperty(target, key, {
    // 可枚舉
    enumerable: true,
    // 不可配置
    configurable: false,
    get: function () {
      return val;
    },
    // 監(jiān)聽器函數
    set: function (value) {
      dep.notify();
    },
  });
}

class Dep {
  constructor() {
    this.subs = [];
  }

  addSub(sub) {
    this.subs.push(sub);
  }

  notify() {
    this.subs.forEach((sub) => {
      sub.update();
    });
  }
}
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市牙肝,隨后出現的幾起案子唉俗,更是在濱河造成了極大的恐慌,老刑警劉巖配椭,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虫溜,死亡現場離奇詭異,居然都是意外死亡颂郎,警方通過查閱死者的電腦和手機吼渡,發(fā)現死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門容为,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乓序,“玉大人,你說我怎么就攤上這事坎背√媾” “怎么了?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵得滤,是天一觀的道長陨献。 經常有香客問我,道長懂更,這世上最難降的妖魔是什么眨业? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任急膀,我火速辦了婚禮,結果婚禮上龄捡,老公的妹妹穿的比我還像新娘卓嫂。我一直安慰自己,他們只是感情好聘殖,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布晨雳。 她就那樣靜靜地躺著,像睡著了一般奸腺。 火紅的嫁衣襯著肌膚如雪餐禁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天突照,我揣著相機與錄音帮非,去河邊找鬼。 笑死绷旗,一個胖子當著我的面吹牛喜鼓,可吹牛的內容都是我干的。 我是一名探鬼主播衔肢,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼庄岖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了角骤?” 一聲冷哼從身側響起隅忿,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎邦尊,沒想到半個月后背桐,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蝉揍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年链峭,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片又沾。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡弊仪,死狀恐怖,靈堂內的尸體忽然破棺而出杖刷,到底是詐尸還是另有隱情励饵,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布滑燃,位于F島的核電站役听,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜典予,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一甜滨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘤袖,春花似錦艳吠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至黍匾,卻和暖如春栏渺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锐涯。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工磕诊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纹腌。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓霎终,卻偏偏與公主長得像,于是被迫代替她去往敵國和親升薯。 傳聞我的和親對象是個殘疾皇子莱褒,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內容