關于Vue框架部分,總會涉及一些高頻面試題,大多數(shù)看似非常初級。 有些純記憶性質的面試題,我們在官方文檔很容易就能查看到。 舉個例子: vue組件之間如何通信? vue生命周期有哪些? 這類面試題在文檔中就能找到答案,網(wǎng)絡上面找到的答案也是千篇一律。大家只要使用過vue并且稍加記憶即可流暢作答。 但是,如果我們也這樣回答,那就算自己真的比其他競爭者更有實力,也很難脫穎而出,更別提獲得高薪offer了。 怎么才能避免這種情況呢? 很簡單,其實面試官提出這類“常見問題”時,就意味著他想要聽到“不常見的答案”。 我們只要將回答問題的方式、思路提升一個層級,給出標新立異的高水準解答,拿下高薪Offer就如探囊取物一般簡單! 下面young村長就帶大家實際操作起來,手把手教你剖析VUE面試題,如何做到“深入淺出”。 (以下內容提取自開課吧全棧課程訓練營) v-if和v-for誰的優(yōu)先級最高? 當面試官提出這個問題時,顯然想要考察應聘者對v-if和v-for的“基本功”,同時還想要考察應聘者如何將理論應用到操作里。 基于以上兩點,我們可以拓展問題: 當v-if和v-for同時出現(xiàn)時,我們應該怎樣優(yōu)化從而獲得更好的性能? 得知了面試官的隱含問題,接下來我們對癥下藥就可以了。 首先,在源碼中找答案: compiler/codegen/index.js(?文件中的位置) 做個測試如下: 兩者同級時,渲染函數(shù)如下: _l包含了isFolder的條件判斷?? 兩者不同級時,渲染函數(shù)如下: 先判斷條件再決定是否執(zhí)行?? 正確解答: 1、顯然v-for優(yōu)先于v-if被解析(把你是怎么知道的告訴面試官) 2、如果同時出現(xiàn),每次渲染都會先執(zhí)行循環(huán)再判斷條件,無論如何循環(huán)都不可避免,浪費了性能 3、要避免出現(xiàn)這種情況,則在外層嵌套template,在這一層進行v-if判斷,然后在內部進行v-for循環(huán) 4、如果條件出現(xiàn)在循環(huán)內部,可通過計算屬性提前過濾掉那些不需要顯示的項 VUE組件data為什么必須是函數(shù) 我們都知道,VUE的data實例必須是函數(shù),那么有沒有與之相反的情況呢?答案是肯定的,因為VUE的根實例就沒有“必須是函數(shù)”這個限制的。 所以,我們在對這道題進行解答之前,我們還要考慮與“VUE組件data對象實例”所對應的“VUE的根實例”。 通過兩者的對比論證,會讓我們的答案更加清晰縝密、更有說服力。 源碼中找答案: src\core\instance\state.js - initData() 文件中的位置? 通過源碼得知: 函數(shù)每次執(zhí)行都會返回全新data對象實例 測試代碼如下: 然而程序甚至無法通過vue檢測?? 正確解答: Vue組件可能存在多個實例,如果使用對象形式定義data,則會導致它們共用一個data對象,那么狀態(tài)變更將會影響所有組件實例,這是不合理的; 采用函數(shù)形式定義,在initData時會將其作為工廠函數(shù)返回全新data對象,有效規(guī)避多實例之間狀態(tài)污染問題。 而在Vue根實例創(chuàng)建過程中則不存在該限制,也是因為根實例只能有一個,不需要擔心這種情況。 vue中key的作用和工作原理 為了表達的更加透徹,我們可以通過對比測試來尋找key的工作原理: 首先是在源碼中找答案,它在文件中的位置是? src\core\vdom\patch.js - updateChildren() 測試代碼如下: ![]() 本次案例代碼重現(xiàn)的是以下過程??: ![]() 在不使用Key的情況下是這樣的??: ![]() 如果使用Key??: // 首次循環(huán)patch A A B C D E A B F C D E // 第2次循環(huán)patch B B C D E B F C D E // 第3次循環(huán)patch E C D E F C D E // 第4次循環(huán)patch D C D F C D // 第5次循環(huán)patch C C F C // oldCh全部處理結束,newCh中剩下的F,創(chuàng)建F并插入到C前面 正確解答: 1、key的作用主要是為了高效的更新虛擬DOM,其原理是vue在patch過程中通過key可以精準判斷兩個節(jié)點是否是同一個,從而避免頻繁更新不同元素,使得整個patch過程更加高效,減少DOM操作量,提高性能。 2、另外,若不設置key還可能在列表更新時引發(fā)一些隱蔽的bug 3、vue中在使用相同標簽名元素的過渡切換時,也會使用到key屬性,其目的也是為了讓vue可以區(qū)分它們,否則vue只會替換其內部屬性而不會觸發(fā)過渡效果。 ![]() 你怎么理解vue中的diff算法? 在分析diff算法之前,我們可以看一下VUE的diff算法模型圖: ![]() 接下來還是先從源碼入手解決問題: 源碼分析1:必要性 lifecycle.js - mountComponent() 組件中可能存在很多個data中的key使用 源碼分析2:執(zhí)行方式 patch.js - patchVnode() patchVnode是diff發(fā)生的地方 整體策略:深度優(yōu)先,同層比較 源碼分析3:高效性 patch.js - updateChildren() 測試代碼如下: ![]() 正確解答: 1、diff算法是虛擬DOM技術的必然產(chǎn)物:通過新舊虛擬DOM作對比(即diff),將變化的地方更新在真實DOM上; 另外,也需要diff高效的執(zhí)行對比過程,從而降低時間復雜度為O(n)。 2、vue 2.x中為了降低Watcher粒度,每個組件只有一個Watcher與之對應,只有引入diff才能精確找到發(fā)生變化的地方。 3、vue中diff執(zhí)行的時刻是組件實例執(zhí)行其更新函數(shù)時,它會比對上一次渲染結果oldVnode和新的渲染結果newVnode,此過程稱為patch。 4、diff過程整體遵循深度優(yōu)先、同層比較的策略;兩個節(jié)點之間比較會根據(jù)它們是否擁有子節(jié)點或者文本節(jié)點做不同操作; 比較兩組子節(jié)點是算法的重點,首先假設頭尾節(jié)點可能相同做4次比對嘗試; 如果沒有找到相同節(jié)點才按照通用方式遍歷查找,查找結束再按情況處理剩下的節(jié)點; 借助key通??梢苑浅>_找到相同節(jié)點,因此整個patch過程非常高效。 |
|