vue高頻面試題(面試路上踩過的坑)


### Vue 雙向綁定原理

mvvm 雙向綁定,采用**數據劫持結合發布者-訂閱者模式**的方式,通過 `Object.defineProperty()` 來劫持各個屬性的 setter、getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。
![雙向綁定原理]( ?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

**幾個要點:**
1、實現一個數據監聽器 Observer,能夠對數據對象的所有屬性進行監聽,如有變動可拿到最新值並通知訂閱者
2、實現一個指令解析器 Compile,對每個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數
3、實現一個 Watcher,作為連接 Observer 和 Compile 的橋梁,能夠訂閱並收到每個屬性變動的通知,執行指令綁定的相應回調函數,從而更新視圖
4、mvvm 入口函數,整合以上三者

**具體步驟:**

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 變更的雙向綁定效果。

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### 描述下 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 相應的更新完成對訂閱者視圖的改變。

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

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

[圖片上傳失敗...(image-b4defe-1573527366002)]

響應式系統簡述:

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

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### 虛擬 DOM 實現原理

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

> 詳細實現見 [面試官: 你對虛擬DOM原理的理解?]( https://user-gold-cdn.xitu.io/2019/8/1/16c49afec13e0416)

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### 既然 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的視圖更新機制對比]( https://blog.csdn.net/csdn_haow/article/details/89915908)

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### Vue 中 key 值的作用?

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

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### Vue 的生命周期

[vue生命周期詳解]( https://juejin.im/post/5c6d48e36fb9a049eb3c84ff)

1.  `beforeCreate`和`created`
2.  `beforeMount`和`mounted`
3.  `beforeUpdate`和`updated`
4.  `beforeDestory`和`destoryed`
5.  `activated`和`deactivated`

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### Vue 組件間通信有哪些方式?

[Vue 組件間通信六種方式]( https://juejin.im/post/5cde0b43f265da03867e78d3)

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

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### watch、methods 和 computed 的區別?

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

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### vue 中怎么重置 data?

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

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

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### 組件中寫 name 選項有什么作用?

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

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### vue-router 有哪些鈎子函數?

官方文檔:[vue-router鈎子函數]( https://router.vuejs.org/zh/guid ... E%E5%AE%88%E5%8D%AB)

*   全局前置守衛 `router.beforeEach`
*   全局解析守衛 `router.beforeResolve`
*   全局后置鈎子 `router.afterEach`
*   路由獨享的守衛 `beforeEnter`
*   組件內的守衛 `beforeRouteEnter`、`beforeRouteUpdate`、`beforeRouteLeave`

[前端路由簡介以及vue-router實現原理]( https://juejin.im/post/5b10b46df265da6e2a08a724)

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### `route` 和 `router` 的區別是什么?

`route`是“路由信息對象”,包括`path`,`params`,`hash`,`query`,`fullPath`,`matched`,`name`等路由信息參數。
`router`是“路由實例對象”,包括了路由的跳轉方法(`push`、`replace`),鈎子函數等。

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### 說一下 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]( https://upload-images.jianshu.io ... imageView2/2/w/1240)

*   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 中再聲明下,這樣顯然是很奇怪但又不得不這樣的做法。

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### Vue 的 nextTick 的原理是什么?

**1\. 為什么需要 nextTick**
      Vue 是異步修改 DOM 的並且不鼓勵開發者直接接觸 DOM,但有時候業務需要必須對數據更改--刷新后的 DOM 做相應的處理,這時候就可以使用 Vue.nextTick(callback)這個 api 了。

**2\. 理解原理前的准備**
      首先需要知道事件循環中宏任務和微任務這兩個概念(這其實也是面試常考點)。請閱大佬文章--[徹底搞懂瀏覽器 Event-loop]( https://juejin.im/post/5c947bca5188257de704121d)
常見的宏任務有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering
常見的微任務有 process.nextTick(Nodejs),Promise.then(), MutationObserver;

**3\. 理解 nextTick**
      而 nextTick 的原理正是 vue 通過異步隊列控制 DOM 更新和 nextTick 回調函數先后執行的方式。如果大家看過這部分的源碼,會發現其中做了很多 isNative()的判斷,因為這里還存在兼容性優雅降級的問題。可見 Vue 開發團隊的深思熟慮,對性能的良苦用心。
如果你比較了解了前面的事件循環原理,推薦你看看這篇文章 請閱大佬文章--[全面解析 Vue.nextTick 實現原理]( https://mp.weixin.qq.com/s/mCcW4OYj3p3471ghMBylBw)

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### Vuex 有哪幾種屬性?

有五種,分別是 `State`、`Getter`、`Mutation`、`Action`、`Module`

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### vue 首屏加載優化

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

![index.html]( ?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

然后找到 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首屏加載優化]( https://www.jianshu.com/p/df198914331b)
[vue項目首屏加載優化實戰]( https://www.cnblogs.com/mianbaodaxia/p/10751453.html)

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### Vue 3.0 有沒有過了解?

      關於Vue 3.0有幸看過尤大的關於3.0版本的[RFC Vue Function-based API RFC]( https://zhuanlan.zhihu.com/p/68477600)。大致說了三個點,第一個是關於提出的新API `setup()`函數,第二個說了對於Typescript的支持,最后說了關於替換`Object.defineProperty`為 Proxy 的支持。
      詳細說了下關於Proxy代替帶來的性能上的提升,因為傳統的原型鏈攔截的方法,無法檢測對象及數組的一些更新操作,但使用Proxy又帶來了瀏覽器兼容問題。

[回到頂部]( https://www.cnblogs.com/chenwenhao/p/11258895.html#_labelTop)

### 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 文件



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM