vue算是很通俗的源碼分析(面試裝逼大法)

1.請你說下數(shù)據(jù)綁定(數(shù)據(jù)綁定原理):

image
  • 首先通過一次渲染操作觸發(fā)Data的getter(這里保證只有視圖中需要被用到的data才會觸發(fā)getter)進(jìn)行依賴收集校哎,這時候其實Watcher與data可以看成一種被綁定的狀態(tài)(實際上是data的閉包中有一個Deps訂閱者,在修改的時候會通知所有的Watcher觀察者)榜轿,在data發(fā)生變化的時候會觸發(fā)它的setter,setter通知Watcher,Watcher進(jìn)行回調(diào)通知組件重新渲染的函數(shù),之后根據(jù)diff算法來決定是否發(fā)生視圖的更新招刹。

初始化data(個人簡化了的initData)

function initData (vm: Component) {
  /*得到data數(shù)據(jù)*/
  let data = vm.$options.data
  
  /*遍歷data,和props對象*/
  const keys = Object.keys(data)
  const props = vm.$options.props
  let i = keys.length

  //遍歷data中的數(shù)據(jù)沥匈,且props和data沒有key沒有沖突
  while (i--) {
      if (!(props && hasOwn(props, keys[i]))) { 
        proxy(vm, `_data`, keys[i])
      }    
      /*這里是我們前面講過的代理蔗喂,將data上面的屬性代理到了vm實例上*/
    }
  }
  /*從這里開始我們要observe了忘渔,開始對數(shù)據(jù)進(jìn)行綁定*/
  observe(data, true /* asRootData */)
}

initData函數(shù)主要做了兩件事:

  • _data上面的數(shù)據(jù)代理到vm實例上
  • 通過observe將所有數(shù)據(jù)變成observable

proxy

/*添加代理*/
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)
}
  • 通過proxy函數(shù)將data上面的數(shù)據(jù)代理到vm上高帖,這樣就可以用app.text代替app._data.text了

Observe

  • Vue的響應(yīng)式數(shù)據(jù)都會有一個ob的屬性作為標(biāo)記,里面存放了該屬性的觀察器畦粮,也就是Observer的實例散址,防止重復(fù)綁定。

  • Observer為數(shù)據(jù)加上響應(yīng)式屬性進(jìn)行雙向綁定宣赔。如果是對象則進(jìn)行深度遍歷预麸,為每一個子對象都綁定上方法,如果是數(shù)組則為每一個成員都綁定上方法儒将。

Watcher

  • Watcher是一個觀察者對象吏祸。依賴收集以后Watcher對象會被保存在Deps中,數(shù)據(jù)變動的時候會由Deps通知Watcher實例钩蚊,然后由Watcher實例回調(diào)cb進(jìn)行視圖的更新贡翘。

Dep

  • Dep是一個發(fā)布者,可以訂閱多個觀察者砰逻,依賴收集之后Deps中會存在一個或多個Watcher對象鸣驱,在數(shù)據(jù)變更的時候通知所有的Watcher。

defineReactive

  • defineReactive的作用是通過Object.defineProperty為數(shù)據(jù)定義上getter\setter方法蝠咆,進(jìn)行依賴收集后閉包中的Deps會存放Watcher對象踊东。觸發(fā)setter改變數(shù)據(jù)的時候會通知Deps訂閱者通知所有的Watcher觀察者對象進(jìn)行試圖的更新北滥。

2.小伙子,說下虛擬dom:

  • 咳咳闸翅,一般來說再芋,我們要修改試圖的話需要直接操作dom執(zhí)行各種事件才行,是應(yīng)用一大就會變得難以維護(hù)缎脾。

  • vnode就是把真實dom都抽象成一顆以js對象構(gòu)成的抽象樹祝闻,在修改抽象樹的數(shù)據(jù)后將抽象樹轉(zhuǎn)換成真實dom重繪到頁面上去。

  • 遗菠,當(dāng)某個抽象樹的某個數(shù)據(jù)被修改的時候联喘,set方法會讓閉包中的Dep調(diào)用notify通知所有訂閱者Watcher,Watcher通過get方法執(zhí)行vm._update(vm._render(),hydrating)

  • 經(jīng)過diff算法只需要修改抽象樹修改了的部分即可辙纬,相對于一大片的HTML修改豁遭,大大提高了性能。

  • Vue使用了這樣的抽象節(jié)點VNode贺拣,它是對真實DOM的一層抽象蓖谢,所以它不依賴某個平臺,比如weex

3.那diff算法你知道怎么運作的嗎譬涡?

  • diff算法在patch方法內(nèi)闪幽,path將通過新老Vnode節(jié)點的對比,根據(jù)兩者的比較結(jié)果進(jìn)行最小單位地修改視圖涡匀,而不是將整個視圖根據(jù)Vnode重繪盯腌。

  • diff算法是通過同層的樹節(jié)點進(jìn)行比較而非對樹進(jìn)行逐層搜索遍歷的方式,所以時間復(fù)雜度是O(n)陨瘩,是非常高效的算法腕够。

  • image
  • 這張圖代表舊的VNode與新VNode進(jìn)行patch的過程,他們只是在同層級的VNode之間進(jìn)行比較得到變化(第二張圖中相同顏色的方塊代表互相進(jìn)行比較的VNode節(jié)點)

4.使用v-for進(jìn)行列表渲染的時候舌劳,加:key的效果是什么帚湘,為什么會這樣?

  • 效果是更高效的更新虛擬dom甚淡。

  • 數(shù)據(jù)更新后大诸,新老Vnode如果是同一節(jié)點,就會直接修改現(xiàn)有的節(jié)點贯卦,否則就是創(chuàng)建新的dom资柔,移除舊的dom

  • 判斷兩個Vnode節(jié)點是否是同一節(jié)點,需要滿足:

    • ==key相同==
    • tag(當(dāng)前節(jié)點的標(biāo)簽名)相同
    • isComment(是否為注釋節(jié)點)相同
    • 是否data(當(dāng)前節(jié)點對應(yīng)的對象脸侥,包含了具體的一些數(shù)據(jù)信息建邓,是一個VNodeData類型,可以參考VNodeData類型中的數(shù)據(jù)信息)都有定義
    • 當(dāng)標(biāo)簽是<input>的時候睁枕,type必須相同
  • 所以官边,這就是為什么盡可能在使用 v-for 時提供key

延伸: 更新虛擬dom的規(guī)則是這樣:

1.如果新舊VNode都是靜態(tài)的沸手,同時它們的key相同(代表同一節(jié)點),并且新的VNode是clone或者是標(biāo)記了once(標(biāo)記v-once屬性注簿,只渲染一次)契吉,那么只需要替換elm以及componentInstance即可。

2.新老節(jié)點均有children子節(jié)點诡渴,則對子節(jié)點進(jìn)行diff操作捐晶,調(diào)用updateChildren,這個updateChildren也是diff的核心妄辩。

3.如果老節(jié)點沒有子節(jié)點而新節(jié)點存在子節(jié)點惑灵,先清空老節(jié)點DOM的文本內(nèi)容,然后為當(dāng)前DOM節(jié)點加入子節(jié)點眼耀。

4.當(dāng)新節(jié)點沒有子節(jié)點而老節(jié)點有子節(jié)點的時候英支,則移除該DOM節(jié)點的所有子節(jié)點。

5.當(dāng)新老節(jié)點都無子節(jié)點的時候哮伟,只是文本的替換干花。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市楞黄,隨后出現(xiàn)的幾起案子池凄,更是在濱河造成了極大的恐慌,老刑警劉巖鬼廓,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肿仑,死亡現(xiàn)場離奇詭異,居然都是意外死亡桑阶,警方通過查閱死者的電腦和手機(jī)柏副,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門勾邦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚣录,“玉大人,你說我怎么就攤上這事眷篇∥樱” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵蕉饼,是天一觀的道長虐杯。 經(jīng)常有香客問我,道長昧港,這世上最難降的妖魔是什么擎椰? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮创肥,結(jié)果婚禮上达舒,老公的妹妹穿的比我還像新娘值朋。我一直安慰自己,他們只是感情好巩搏,可當(dāng)我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布昨登。 她就那樣靜靜地躺著,像睡著了一般贯底。 火紅的嫁衣襯著肌膚如雪丰辣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天禽捆,我揣著相機(jī)與錄音笙什,去河邊找鬼。 笑死胚想,一個胖子當(dāng)著我的面吹牛得湘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顿仇,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淘正,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了臼闻?” 一聲冷哼從身側(cè)響起鸿吆,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎述呐,沒想到半個月后惩淳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡乓搬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年思犁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片进肯。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡激蹲,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出江掩,到底是詐尸還是另有隱情学辱,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布环形,位于F島的核電站策泣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏抬吟。R本人自食惡果不足惜萨咕,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望火本。 院中可真熱鬧危队,春花似錦蓄喇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盅弛,卻和暖如春钱骂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挪鹏。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工见秽, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讨盒。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓解取,卻偏偏與公主長得像,于是被迫代替她去往敵國和親返顺。 傳聞我的和親對象是個殘疾皇子禀苦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容