面試必備的13道能夠觸類旁通的Vue面試題

本文首發於微信公衆號「程序員面試官」前端

前言

Vue框架部分咱們會涉及一些高頻且有必定探討價值的面試題,咱們不會涉及一些很是初級的在官方文檔就能查看的純記憶性質的面試題,好比:vue

  • vue經常使用的修飾符?
  • vue-cli 工程經常使用的 npm 命令有哪些?
  • vue中 keep-alive 組件的做用?

首先,上述類型的面試題在文檔中可查,沒有比官方文檔更權威的答案了,其次這種問題沒有太大價值,除了考察候選人的記憶力,最後,這種面試題只要用過vue的都知道,沒有必要佔用咱們的篇幅.node

咱們的問題並很少,可是難度可能會高一些,若是你真的搞懂了這些問題,在絕大多數狀況下會有觸類旁通的效果,能夠說基本能拿下Vue相關的全部重要知識點了.程序員

你對MVVM的理解?

MVVM是什麼?

MVVM 模式,顧名思義即 Model-View-ViewModel 模式。它萌芽於2005年微軟推出的基於 Windows 的用戶界面框架 WPF ,前端最先的 MVVM 框架 knockout 在2010年發佈。面試

Model 層: 對應數據層的域模型,它主要作域模型的同步。經過 Ajax/fetch 等 API 完成客戶端和服務端業務 Model 的同步。在層間關係裏,它主要用於抽象出 ViewModel 中視圖的 Model。算法

View 層:做爲視圖模板存在,在 MVVM 裏,整個 View 是一個動態模板。除了定義結構、佈局外,它展現的是 ViewModel 層的數據和狀態。View 層不負責處理狀態,View 層作的是 數據綁定的聲明、 指令的聲明、 事件綁定的聲明。vuex

ViewModel 層:把 View 須要的層數據暴露,並對 View 層的 數據綁定聲明、 指令聲明、 事件綁定聲明 負責,也就是處理 View 層的具體業務邏輯。ViewModel 底層會作好綁定屬性的監聽。當 ViewModel 中數據變化,View 層會獲得更新;而當 View 中聲明瞭數據的雙向綁定(一般是表單元素),框架也會監聽 View 層(表單)值的變化。一旦值變化,View 層綁定的 ViewModel 中的數據也會獲得自動更新。vue-cli

2019-07-16-21-47-05

MVVM的優缺點?

優勢:npm

  1. 分離視圖(View)和模型(Model),下降代碼耦合,提升視圖或者邏輯的重用性: 好比視圖(View)能夠獨立於Model變化和修改,一個ViewModel能夠綁定不一樣的"View"上,當View變化的時候Model不能夠不變,當Model變化的時候View也能夠不變。你能夠把一些視圖邏輯放在一個ViewModel裏面,讓不少view重用這段視圖邏輯
  2. 提升可測試性: ViewModel的存在能夠幫助開發者更好地編寫測試代碼
  3. 自動更新dom: 利用雙向綁定,數據更新後視圖自動更新,讓開發者從繁瑣的手動dom中解放

缺點:數組

  1. Bug很難被調試: 由於使用雙向綁定的模式,當你看到界面異常了,有多是你View的代碼有Bug,也多是Model的代碼有問題。數據綁定使得一個位置的Bug被快速傳遞到別的位置,要定位原始出問題的地方就變得不那麼容易了。另外,數據綁定的聲明是指令式地寫在View的模版當中的,這些內容是沒辦法去打斷點debug的
  2. 一個大的模塊中model也會很大,雖然使用方便了也很容易保證了數據的一致性,當時長期持有,不釋放內存就形成了花費更多的內存
  3. 對於大型的圖形應用程序,視圖狀態較多,ViewModel的構建和維護的成本都會比較高

你對Vue生命週期的理解?

生命週期是什麼

Vue 實例有一個完整的生命週期,也就是從開始建立、初始化數據、編譯模版、掛載Dom -> 渲染、更新 -> 渲染、卸載等一系列過程,咱們稱這是Vue的生命週期。

各個生命週期的做用

生命週期 描述
beforeCreate 組件實例被建立之初,組件的屬性生效以前
created 組件實例已經徹底建立,屬性也綁定,但真實dom尚未生成,$el還不可用
beforeMount 在掛載開始以前被調用:相關的 render 函數首次被調用
mounted el 被新建立的 vm.$el 替換,並掛載到實例上去以後調用該鉤子
beforeUpdate 組件數據更新以前調用,發生在虛擬 DOM 打補丁以前
update 組件數據更新以後
activited keep-alive專屬,組件被激活時調用
deadctivated keep-alive專屬,組件被銷燬時調用
beforeDestory 組件銷燬前調用
destoryed 組件銷燬後調用

生命週期示意圖

2019-06-23-05-03-43

異步請求適合在哪一個生命週期調用?

官方實例的異步請求是在mounted生命週期中調用的,而實際上也能夠在created生命週期中調用。

Vue組件如何通訊?

Vue組件通訊的方法以下:

  • props/$emit+v-on: 經過props將數據自上而下傳遞,而經過$emit和v-on來向上傳遞信息。
  • EventBus: 經過EventBus進行信息的發佈與訂閱
  • vuex: 是全局數據管理庫,能夠經過vuex管理全局的數據流
  • $attrs/$listeners: Vue2.4中加入的$attrs/$listeners能夠進行跨級的組件通訊
  • provide/inject:以容許一個祖先組件向其全部子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效,這成爲了跨組件通訊的基礎

還有一些用solt插槽或者ref實例進行通訊的,使用場景過於有限就不贅述了。

computed和watch有什麼區別?

computed:

  1. computed是計算屬性,也就是計算值,它更多用於計算值的場景
  2. computed具備緩存性,computed的值在getter執行後是會緩存的,只有在它依賴的屬性值改變以後,下一次獲取computed的值時纔會從新調用對應的getter來計算
  3. computed適用於計算比較消耗性能的計算場景

watch:

  1. 更多的是「觀察」的做用,相似於某些數據的監聽回調,用於觀察props $emit或者本組件的值,當數據變化時來執行回調進行後續操做
  2. 無緩存性,頁面從新渲染時值不變化也會執行

小結:

  1. 當咱們要進行數值計算,並且依賴於其餘數據,那麼把這個數據設計爲computed
  2. 若是你須要在某個數據變化時作一些事情,使用watch來觀察這個數據變化

Vue是如何實現雙向綁定的?

利用Object.defineProperty劫持對象的訪問器,在屬性值發生變化時咱們能夠獲取變化,而後根據變化進行後續響應,在vue3.0中經過Proxy代理對象進行相似的操做。

// 這是將要被劫持的對象
const data = {
  name: '',
};

function say(name) {
  if (name === '古天樂') {
    console.log('給你們推薦一款超好玩的遊戲');
  } else if (name === '渣渣輝') {
    console.log('戲我演過不少,可遊戲我只玩貪玩懶月');
  } else {
    console.log('來作個人兄弟');
  }
}

// 遍歷對象,對其屬性值進行劫持
Object.keys(data).forEach(function(key) {
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get: function() {
      console.log('get');
    },
    set: function(newVal) {
      // 當屬性值發生變化時咱們能夠進行額外操做
      console.log(`你們好,我係${newVal}`);
      say(newVal);
    },
  });
});

data.name = '渣渣輝';
//你們好,我係渣渣輝
//戲我演過不少,可遊戲我只玩貪玩懶月
複製代碼

詳細實現見Proxy比defineproperty優劣對比?

Proxy與Object.defineProperty的優劣對比?

Proxy的優點以下:

  • Proxy能夠直接監聽對象而非屬性
  • Proxy能夠直接監聽數組的變化
  • Proxy有多達13種攔截方法,不限於apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具有的
  • Proxy返回的是一個新對象,咱們能夠只操做新的對象達到目的,而Object.defineProperty只能遍歷對象屬性直接修改
  • Proxy做爲新標準將受到瀏覽器廠商重點持續的性能優化,也就是傳說中的新標準的性能紅利

Object.defineProperty的優點以下:

  • 兼容性好,支持IE9

詳細實現見Proxy比defineproperty優劣對比?

你是如何理解Vue的響應式系統的?

2019-07-22-16-29-59

響應式系統簡述:

  • 任何一個 Vue Component 都有一個與之對應的 Watcher 實例。
  • Vue 的 data 上的屬性會被添加 getter 和 setter 屬性。
  • 當 Vue Component render 函數被執行的時候, data 上會被 觸碰(touch), 即被讀, getter 方法會被調用, 此時 Vue 會去記錄此 Vue component 所依賴的全部 data。(這一過程被稱爲依賴收集)
  • data 被改動時(主要是用戶操做), 即被寫, setter 方法會被調用, 此時 Vue 會去通知全部依賴於此 data 的組件去調用他們的 render 函數進行更新。

虛擬DOM的優劣如何?

優勢:

  • 保證性能下限: 虛擬DOM能夠通過diff找出最小差別,而後批量進行patch,這種操做雖然比不上手動優化,可是比起粗暴的DOM操做性能要好不少,所以虛擬DOM能夠保證性能下限
  • 無需手動操做DOM: 虛擬DOM的diff和patch都是在一次更新中自動進行的,咱們無需手動操做DOM,極大提升開發效率
  • 跨平臺: 虛擬DOM本質上是JavaScript對象,而DOM與平臺強相關,相比之下虛擬DOM能夠進行更方便地跨平臺操做,例如服務器渲染、移動端開發等等

缺點:

  • 沒法進行極致優化: 在一些性能要求極高的應用中虛擬DOM沒法進行鍼對性的極致優化,好比VScode採用直接手動操做DOM的方式進行極端的性能優化

虛擬DOM實現原理?

  • 虛擬DOM本質上是JavaScript對象,是對真實DOM的抽象
  • 狀態變動時,記錄新樹和舊樹的差別
  • 最後把差別更新到真正的dom中

詳細實現見虛擬DOM原理?

既然Vue經過數據劫持能夠精準探測數據變化,爲何還須要虛擬DOM進行diff檢測差別?

考點: Vue的變化偵測原理

前置知識: 依賴收集、虛擬DOM、響應式系統

現代前端框架有兩種方式偵測變化,一種是pull一種是push

pull: 其表明爲React,咱們能夠回憶一下React是如何偵測到變化的,咱們一般會用setStateAPI顯式更新,而後React會進行一層層的Virtual Dom Diff操做找出差別,而後Patch到DOM上,React從一開始就不知道究竟是哪發生了變化,只是知道「有變化了」,而後再進行比較暴力的Diff操做查找「哪發生變化了」,另一個表明就是Angular的髒檢查操做。

push: Vue的響應式系統則是push的表明,當Vue程序初始化的時候就會對數據data進行依賴的收集,一但數據發生變化,響應式系統就會馬上得知,所以Vue是一開始就知道是「在哪發生變化了」,可是這又會產生一個問題,若是你熟悉Vue的響應式系統就知道,一般一個綁定一個數據就須要一個Watcher,一但咱們的綁定細粒度太高就會產生大量的Watcher,這會帶來內存以及依賴追蹤的開銷,而細粒度太低會沒法精準偵測變化,所以Vue的設計是選擇中等細粒度的方案,在組件級別進行push偵測的方式,也就是那套響應式系統,一般咱們會第一時間偵測到發生變化的組件,而後在組件內部進行Virtual Dom Diff獲取更加具體的差別,而Virtual Dom Diff則是pull操做,Vue是push+pull結合的方式進行變化偵測的.

Vue爲何沒有相似於React中shouldComponentUpdate的生命週期?

考點: Vue的變化偵測原理

前置知識: 依賴收集、虛擬DOM、響應式系統

根本緣由是Vue與React的變化偵測方式有所不一樣

React是pull的方式偵測變化,當React知道發生變化後,會使用Virtual Dom Diff進行差別檢測,可是不少組件其實是確定不會發生變化的,這個時候須要用shouldComponentUpdate進行手動操做來減小diff,從而提升程序總體的性能.

Vue是pull+push的方式偵測變化的,在一開始就知道那個組件發生了變化,所以在push的階段並不須要手動控制diff,而組件內部採用的diff方式其實是能夠引入相似於shouldComponentUpdate相關生命週期的,可是一般合理大小的組件不會有過量的diff,手動優化的價值有限,所以目前Vue並無考慮引入shouldComponentUpdate這種手動優化的生命週期.

Vue中的key到底有什麼用?

key是爲Vue中的vnode標記的惟一id,經過這個key,咱們的diff操做能夠更準確、更快速

diff算法的過程當中,先會進行新舊節點的首尾交叉對比,當沒法匹配的時候會用新節點的key與舊節點進行比對,而後超出差別.

diff程能夠歸納爲:oldCh和newCh各有兩個頭尾的變量StartIdx和EndIdx,它們的2個變量相互比較,一共有4種比較方式。若是4種比較都沒匹配,若是設置了key,就會用key進行比較,在比較的過程當中,變量會往中間靠,一旦StartIdx>EndIdx代表oldCh和newCh至少有一個已經遍歷完了,就會結束比較,這四種比較方式就是首、尾、舊尾新頭、舊頭新尾.

  • 準確: 若是不加key,那麼vue會選擇複用節點(Vue的就地更新策略),致使以前節點的狀態被保留下來,會產生一系列的bug.
  • 快速: key的惟一性能夠被Map數據結構充分利用,相比於遍歷查找的時間複雜度O(n),Map的時間複雜度僅僅爲O(1).

2019-07-26-14-52-57


相關文章
相關標籤/搜索