2019前端面試系列——Vue面試題

Vue 雙向綁定原理

mvvm 雙向綁定,採用數據劫持結合發佈者-訂閱者模式的方式,經過 Object.defineProperty() 來劫持各個屬性的 setter、getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。
雙向綁定原理css

幾個要點:
一、實現一個數據監聽器 Observer,可以對數據對象的全部屬性進行監聽,若有變更可拿到最新值並通知訂閱者
二、實現一個指令解析器 Compile,對每一個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數
三、實現一個 Watcher,做爲鏈接 Observer 和 Compile 的橋樑,可以訂閱並收到每一個屬性變更的通知,執行指令綁定的相應回調函數,從而更新視圖
四、mvvm 入口函數,整合以上三者html

具體步驟:前端

  1. 須要 observe 的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter 和 getter
    這樣的話,給這個對象的某個值賦值,就會觸發 setter,那麼就能監聽到了數據變化
  2. compile 解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖
  3. Watcher 訂閱者是 Observer 和 Compile 之間通訊的橋樑,主要作的事情是:
    • 在自身實例化時往屬性訂閱器(dep)裏面添加本身
    • 自身必須有一個 update() 方法
    • 待屬性變更 dep.notice() 通知時,能調用自身的 update() 方法,並觸發 Compile 中綁定的回調,則功成身退。
  4. MVVM 做爲數據綁定的入口,整合 Observer、Compile 和 Watcher 三者,經過Observer來監聽本身的 model 數據變化,經過 Compile 來解析編譯模板指令,最終利用 Watcher 搭起 Observer 和 Compile 之間的通訊橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據 model 變動的雙向綁定效果。

描述下 vue 從初始化頁面--修改數據--刷新頁面 UI 的過程?

      當 Vue 進入初始化階段時,一方面 Vue 會遍歷 data 中的屬性,並用 Object.defineProperty 將它轉化成 getter/setter 的形式,實現數據劫持(暫不談 Vue3.0 的 Proxy);另外一方面,Vue 的指令編譯器 Compiler 對元素節點的各個指令進行解析,初始化視圖,並訂閱 Watcher 來更新試圖,此時 Watcher 會將本身添加到消息訂閱器 Dep 中,此時初始化完畢。
      當數據發生變化時,觸發 Observer 中 setter 方法,當即調用 Dep.notify(),Dep 這個數組開始遍歷全部的訂閱者,並調用其 update 方法,Vue 內部再經過 diff 算法,patch 相應的更新完成對訂閱者視圖的改變。vue

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

vue響應系統
響應式系統簡述:node

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

虛擬 DOM 實現原理

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

詳細實現見 面試官: 你對虛擬DOM原理的理解?react

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

考點: Vue 的變化偵測原理
前置知識: 依賴收集、虛擬 DOM、響應式系統
現代前端框架有兩種方式偵測變化,一種是pull,一種是pushwebpack

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

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

Vue和React的視圖更新機制對比面試

Vue 中 key 值的做用?

      當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用「就地複用」策略。若是數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單複用此處每一個元素,而且確保它在特定索引下顯示已被渲染過的每一個元素。key 的做用主要是爲了高效的更新虛擬DOM

Vue 的生命週期

vue生命週期詳解

  1. beforeCreatecreated
  2. beforeMountmounted
  3. beforeUpdateupdated
  4. beforeDestorydestoryed
  5. activateddeactivated

Vue 組件間通訊有哪些方式?

Vue 組件間通訊六種方式

  1. props/$emit
  2. $emit/$on
  3. vuex
  4. $attrs/$listeners
  5. provide/inject
  6. $parent/$children 與 ref

watch、methods 和 computed 的區別?

  • watch 爲了監聽某個響應數據的變化。computed 是自動監聽依賴值的變化,從而動態返回內容,主要目的是簡化模板內的複雜運算。因此區別來源於用法,只是須要動態值,那就用 computed ;須要知道值的改變後執行業務邏輯,才用 watch。
  • methods是一個方法,它能夠接受參數,而computed 不能,computed 是能夠緩存的,methods 不會。computed 能夠依賴其餘 computed,甚至是其餘組件的 data。

vue 中怎麼重置 data?

使用Object.assign(),vm.$data能夠獲取當前狀態下的data,vm.$options.data能夠獲取到組件初始化狀態下的data。

Object.assign(this.$data, this.$options.data())

組件中寫 name 選項有什麼做用?

  1. 項目使用 keep-alive 時,可搭配組件 name 進行緩存過濾
  2. DOM 作遞歸組件時須要調用自身 name
  3. vue-devtools 調試工具裏顯示的組見名稱是由vue中組件name決定的

vue-router 有哪些鉤子函數?

官方文檔:vue-router鉤子函數

  • 全局前置守衛 router.beforeEach
  • 全局解析守衛 router.beforeResolve
  • 全局後置鉤子 router.afterEach
  • 路由獨享的守衛 beforeEnter
  • 組件內的守衛 beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave

前端路由簡介以及vue-router實現原理

routerouter 的區別是什麼?

route是「路由信息對象」,包括path,params,hash,query,fullPath,matched,name等路由信息參數。
router是「路由實例對象」,包括了路由的跳轉方法(pushreplace),鉤子函數等。

說一下 Vue 和 React 的認識,作一個簡單的對比

1.監聽數據變化的實現原理不一樣

  • Vue 經過 getter/setter 以及一些函數的劫持,能精確快速的計算出 Virtual DOM 的差別。這是因爲它在渲染過程當中,會跟蹤每個組件的依賴關係,不須要從新渲染整個組件樹。
  • React 默認是經過比較引用的方式進行的,若是不優化,每當應用的狀態被改變時,所有子組件都會從新渲染,可能致使大量沒必要要的 VDOM 的從新渲染。

      Vue 不須要特別的優化就能達到很好的性能,而對於 React 而言,須要經過 PureComponent/shouldComponentUpdate 這個生命週期方法來進行控制。若是你的應用中,交互複雜,須要處理大量的 UI 變化,那麼使用 Virtual DOM 是一個好主意。若是你更新元素並不頻繁,那麼 Virtual DOM 並不必定適用,性能極可能還不如直接操控 DOM。

      爲何 React 不精確監聽數據變化呢?這是由於 Vue 和 React 設計理念上的區別,Vue 使用的是可變數據,而 React 更強調數據的不可變。

2.數據流的不一樣
cmd-markdown-logo

  • Vue 中默認支持雙向綁定,組件與 DOM 之間能夠經過 v-model 雙向綁定。可是,父子組件之間,props 在 2.x 版本是單向數據流
  • React 一直提倡的是單向數據流,他稱之爲 onChange/setState()模式。

      不過因爲咱們通常都會用 Vuex 以及 Redux 等單向數據流的狀態管理框架,所以不少時候咱們感覺不到這一點的區別了。

3.模板渲染方式的不一樣

在表層上,模板的語法不一樣

  • React 是經過 JSX 渲染模板
  • 而 Vue 是經過一種拓展的 HTML 語法進行渲染

在深層上,模板的原理不一樣,這纔是他們的本質區別:

  • React 是在組件 JS 代碼中,經過原生 JS 實現模板中的常見語法,好比插值,條件,循環等,都是經過 JS 語法實現的
  • Vue 是在和組件 JS 代碼分離的單獨的模板中,經過指令來實現的,好比條件語句就須要 v-if 來實現

      對這一點,我我的比較喜歡 React 的作法,由於他更加純粹更加原生,而 Vue 的作法顯得有些獨特,會把 HTML 弄得很亂。舉個例子,說明 React 的好處:react 中 render 函數是支持閉包特性的,因此咱們 import 的組件在 render 中能夠直接調用。可是在 Vue 中,因爲模板中使用的數據都必須掛在 this 上進行一次中轉,因此咱們 import 一個組件完了以後,還須要在 components 中再聲明下,這樣顯然是很奇怪但又不得不這樣的作法。

Vue 的 nextTick 的原理是什麼?

1. 爲何須要 nextTick
      Vue 是異步修改 DOM 的而且不鼓勵開發者直接接觸 DOM,但有時候業務須要必須對數據更改--刷新後的 DOM 作相應的處理,這時候就可使用 Vue.nextTick(callback)這個 api 了。

2. 理解原理前的準備
      首先須要知道事件循環中宏任務和微任務這兩個概念(這其實也是面試常考點)。請閱大佬文章--完全搞懂瀏覽器 Event-loop
常見的宏任務有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering
常見的微任務有 process.nextTick(Nodejs),Promise.then(), MutationObserver;

3. 理解 nextTick
      而 nextTick 的原理正是 vue 經過異步隊列控制 DOM 更新和 nextTick 回調函數前後執行的方式。若是你們看過這部分的源碼,會發現其中作了不少 isNative()的判斷,由於這裏還存在兼容性優雅降級的問題。可見 Vue 開發團隊的深思熟慮,對性能的良苦用心。
若是你比較瞭解了前面的事件循環原理,推薦你看看這篇文章 請閱大佬文章--全面解析 Vue.nextTick 實現原理

Vuex 有哪幾種屬性?

有五種,分別是 StateGetterMutationActionModule

vue 首屏加載優化

1. 把不常改變的庫放到 index.html 中,經過 cdn 引入

index.html
而後找到 build/webpack.base.conf.js 文件,在 module.exports = { } 中添加如下代碼

externals: {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'element-ui': 'ELEMENT',
},

這樣 webpack 就不會把 vue.js, vue-router, element-ui 庫打包了。聲明一下,我把 main.js 中對 element 的引入刪掉了,否則我發現打包後的 app.css 仍是會把 element 的 css 打包進去,刪掉後就沒了。
而後你打包就會發現 vendor 文件小了不少~

2. vue 路由的懶加載

import或者require懶加載。你打包就會發現,多了不少 1.xxxxx.js;2.xxxxx.js 等等,而 vendor.xxx.js 沒了,剩下 app.js 和 manifest.js,並且 app.js 還很小,我這裏是 100k 多一點。

3. 不生成 map 文件

找到 config/index.js,修改成 productionSourceMap: false

4. vue 組件儘可能不要全局引入
5. 使用更輕量級的工具庫
6. 開啓gzip壓縮

這個優化是兩方面的,前端將文件打包成.gz文件,而後經過nginx的配置,讓瀏覽器直接解析.gz文件。

7. 首頁單獨作服務端渲染

若是首頁真的有瓶頸,能夠考慮用 node 單獨作服務端渲染,而下面的子頁面仍用 spa 單頁的方式交互。
這裏不推薦直接用 nuxt.js 服務端渲染方案,由於這樣一來增長了學習成本,二來服務端的維護成本也會上升,有時在本機測試沒問題,在服務端跑就有問題,爲了省心,仍是最大限度的使用靜態頁面較好。

參考連接:
vue首屏加載優化
vue項目首屏加載優化實戰

Vue 3.0 有沒有過了解?

      關於Vue 3.0有幸看過尤大的關於3.0版本的RFC Vue Function-based API RFC。大體說了三個點,第一個是關於提出的新API setup()函數,第二個說了對於Typescript的支持,最後說了關於替換Object.defineProperty爲 Proxy 的支持。
      詳細說了下關於Proxy代替帶來的性能上的提高,由於傳統的原型鏈攔截的方法,沒法檢測對象及數組的一些更新操做,但使用Proxy又帶來了瀏覽器兼容問題。

vue-cli 替咱們作了哪些工做?

首先須要知道 vue-cli 是什麼?它是基於 Vue.js 進行快速開發的完整系統,也能夠理解成是不少 npm 包的集合。其次,vue-cli 完成的功能有哪些?

.vue 文件 --> .js 文件
ES6 語法 --> ES5 語法
Sass,Less,Stylus --> CSS
對 jpg,png,font 等靜態資源的處理
熱更新
定義環境變量,區分 dev 和 production 模式
...

若是開發者須要補充或修改默認設置,須要在 package.json 同級下新建一個 vue.config.js 文件

更多vue面試題:
面試必備的13道能夠觸類旁通的Vue面試題
vue 248個知識點(面試題)爲你保駕護航


2019前端面試系列——CSS面試題
2019前端面試系列——JS面試題
2019前端面試系列——JS高頻手寫代碼題
2019前端面試系列——Vue面試題
2019前端面試系列——HTTP、瀏覽器面試題

相關文章
相關標籤/搜索