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