vue面試題+答案,2021前端面試
vue視頻教程系列:
Vue3+ElementPlus+Koa2 全棧開發后台系統
試看:點擊觀看
完整課程:點擊查看
Vue3.0高階實戰:開發高質量音樂Web app
試看:點擊觀看
完整課程:點擊查看
VUE全面教學+VUE開源項目超級實戰:
試看:點擊觀看
完整課程:點擊查看
最新Vue.JS教程快速入門到項目實戰(Vue3/VueJS技術詳解)
試看:點擊觀看
完整課程:點擊查看
最新最全前端畢設項目(小程序+VUE+Noed+React+uni app+Express+Mongodb)
試看:點擊觀看
完整課程:點擊查看
MVC 和 MVVM 區別
MVC
MVC 全名是 Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,一種軟件設計典范
- Model(模型):是應用程序中用於處理應用程序數據邏輯的部分。通常模型對象負責在數據庫中存取數據
- View(視圖):是應用程序中處理數據顯示的部分。通常視圖是依據模型數據創建的
- Controller(控制器):是應用程序中處理用戶交互的部分。通常控制器負責從視圖讀取數據,控制用戶輸入,並向模型發送數據
MVC 的思想:一句話描述就是 Controller 負責將 Model 的數據用 View 顯示出來,換句話說就是在 Controller 里面把 Model 的數據賦值給 View。
MVVM
MVVM 新增了 VM 類
- ViewModel 層:做了兩件事達到了數據的雙向綁定 一是將【模型】轉化成【視圖】,即將后端傳遞的數據轉化成所看到的頁面。實現的方式是:數據綁定。二是將【視圖】轉化成【模型】,即將所看到的頁面轉化成后端的數據。實現的方式是:DOM 事件監聽。
MVVM 與 MVC 最大的區別就是:它實現了 View 和 Model 的自動同步,也就是當 Model 的屬性改變時,我們不用再自己手動操作 Dom 元素,來改變 View 的顯示,而是改變屬性后該屬性對應 View 層顯示會自動改變(對應Vue數據驅動的思想)
整體看來,MVVM 比 MVC 精簡很多,不僅簡化了業務與界面的依賴,還解決了數據頻繁更新的問題,不用再用選擇器操作 DOM 元素。因為在 MVVM 中,View 不知道 Model 的存在,Model 和 ViewModel 也觀察不到 View,這種低耦合模式提高代碼的可重用性
注意:Vue 並沒有完全遵循 MVVM 的思想 這一點官網自己也有說明
那么問題來了 為什么官方要說 Vue 沒有完全遵循 MVVM 思想呢?
- 嚴格的 MVVM 要求 View 不能和 Model 直接通信,而 Vue 提供了$refs 這個屬性,讓 Model 可以直接操作 View,違反了這一規定,所以說 Vue 沒有完全遵循 MVVM。
vue是如何實現響應式數據的呢?(響應式數據原理)
Vue2: Object.defineProperty
重新定義 data
中所有的屬性, Object.defineProperty
可以使數據的獲取與設置增加一個攔截的功能,攔截屬性的獲取,進行依賴收集。攔截屬性的更新操作,進行通知。
具體的過程:首先Vue使用 initData
初始化用戶傳入的參數,然后使用 new Observer
對數據進行觀測,如果數據是一個對象類型就會調用 this.walk(value)
對對象進行處理,內部使用 defineeReactive
循環對象屬性定義響應式變化,核心就是使用 Object.defineProperty
重新定義數據。
那vue中是如何檢測數組變化的呢?
數組就是使用 object.defineProperty
重新定義數組的每一項,那能引起數組變化的方法我們都是知道的, pop
、 push
、 shift
、 unshift
、 splice
、 sort
、 reverse
這七種,只要這些方法執行改了數組內容,我就更新內容就好了,是不是很好理解。
- 是用來函數劫持的方式,重寫了數組方法,具體呢就是更改了數組的原型,更改成自己的,用戶調數組的一些方法的時候,走的就是自己的方法,然后通知視圖去更新。
- 數組里每一項可能是對象,那么我就是會對數組的每一項進行觀測,(且只有數組里的對象才能進行觀測,觀測過的也不會進行觀測)
vue3:改用 proxy
,可直接監聽對象數組的變化。
vue的優點
輕量級框架:只關注視圖層,是一個構建數據的視圖集合,大小只有幾十kb;
簡單易學:國人開發,中文文檔,不存在語言障礙 ,易於理解和學習;
雙向數據綁定:保留了angular的特點,在數據操作方面更為簡單;
組件化:保留了react的優點,實現了html的封裝和重用,在構建單頁面應用方面有着獨特的優勢;
視圖,數據,結構分離:使數據的更改更為簡單,不需要進行邏輯代碼的修改,只需要操作數據就能完成相關操作;
虛擬DOM:dom操作是非常耗費性能的,不再使用原生的dom操作節點,極大解放dom操作,但具體操作的還是dom不過是換了另一種方式;
運行速度更快:相比較與react而言,同樣是操作虛擬dom,就性能而言,vue存在很大的優勢。
為什么vue組件中data必須是一個函數?
對象為引用類型,當復用組件時,由於數據對象都指向同一個data對象,當在一個組件中修改data時,其他重用的組件中的data會同時被修改;而使用返回對象的函數,由於每次返回的都是一個新對象(Object的實例),引用地址不同,則不會出現這個問題。
v-if 和 v-show 的區別
v-if 在編譯過程中會被轉化成三元表達式,條件不滿足時不渲染此節點。
v-show 會被編譯成指令,條件不滿足時控制樣式將對應節點隱藏 (display:none)
為什么Vue采用異步渲染呢?
Vue
是組件級更新,如果不采用異步更新,那么每次更新數據都會對當前組件進行重新渲染,所以為了性能, Vue
會在本輪數據更新后,在異步更新視圖。核心思想 nextTick
。
dep.notify()
通知 watcher進行更新, subs[i].update
依次調用 watcher 的 update
, queueWatcher
將watcher 去重放入隊列, nextTick( flushSchedulerQueue
)在下一tick中刷新watcher隊列(異步)。
父子組件生命周期調用順序(簡單)
渲染順序:先父后子,完成順序:先子后父
更新順序:父更新導致子更新,子更新完成后父
銷毀順序:先父后子,完成順序:先子后父
用VNode來描述一個DOM結構
虛擬節點就是用一個對象來描述一個真實的DOM元素。首先將 template
(真實DOM)先轉成 ast
, ast
樹通過 codegen
生成 render
函數, render
函數里的 _c
方法將它轉為虛擬dom
diff算法
時間復雜度: 個樹的完全 diff
算法是一個時間復雜度為 O(n*3)
,vue進行優化轉化成 O(n)
。
理解:
- 最小量更新,
key
很重要。這個可以是這個節點的唯一標識,告訴diff
算法,在更改前后它們是同一個DOM節點- 擴展
v-for
為什么要有key
,沒有key
會暴力復用,舉例子的話隨便說一個比如移動節點或者增加節點(修改DOM),加key
只會移動減少操作DOM。
- 擴展
- 只有是同一個虛擬節點才會進行精細化比較,否則就是暴力刪除舊的,插入新的。
- 只進行同層比較,不會進行跨層比較。
diff算法的優化策略:四種命中查找,四個指針
- 舊前與新前(先比開頭,后插入和刪除節點的這種情況)
- 舊后與新后(比結尾,前插入或刪除的情況)
- 舊前與新后(頭與尾比,此種發生了,涉及移動節點,那么新前指向的節點,移動到舊后之后)
- 舊后與新前(尾與頭比,此種發生了,涉及移動節點,那么新前指向的節點,移動到舊前之前)
v-for 為什么要加 key
如果不使用 key,Vue 會使用一種最大限度減少動態元素並且盡可能的嘗試就地修改/復用相同類型元素的算法。key 是為 Vue 中 vnode 的唯一標記,通過這個 key,我們的 diff 操作可以更准確、更快速
更准確:因為帶 key 就不是就地復用了,在 sameNode 函數 a.key === b.key 對比中可以避免就地復用的情況。所以會更加准確。
更快速:利用 key 的唯一性生成 map 對象來獲取對應節點,比遍歷方式更快
vue-router 路由鈎子函數是什么 執行順序是什么
路由鈎子的執行流程, 鈎子函數種類有:全局守衛、路由守衛、組件守衛
完整的導航解析流程:
- 導航被觸發。
- 在失活的組件里調用 beforeRouteLeave 守衛。
- 調用全局的 beforeEach 守衛。
- 在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)。
- 在路由配置里調用 beforeEnter。
- 解析異步路由組件。
- 在被激活的組件里調用 beforeRouteEnter。
- 調用全局的 beforeResolve 守衛 (2.5+)。
- 導航被確認。
- 調用全局的 afterEach 鈎子。
- 觸發 DOM 更新。
- 調用 beforeRouteEnter 守衛中傳給 next 的回調函數,創建好的組件實例會作為回調函數的參數傳入。
談一下對 vuex 的個人理解
vuex 是專門為 vue 提供的全局狀態管理系統,用於多個組件中數據共享、數據緩存等。(無法持久化、內部核心原理是通過創造一個全局實例 new Vue)
主要包括以下幾個模塊:
- State:定義了應用狀態的數據結構,可以在這里設置默認的初始狀態。
- Getter:允許組件從 Store 中獲取數據,mapGetters 輔助函數僅僅是將 store 中的 getter 映射到局部計算屬性。
- Mutation:是唯一更改 store 中狀態的方法,且必須是同步函數。
- Action:用於提交 mutation,而不是直接變更狀態,可以包含任意異步操作。
- Module:允許將單一的 Store 拆分為多個 store 且同時保存在單一的狀態樹中。
keep-alive 使用場景和原理
keep-alive 是 Vue 內置的一個組件,可以實現組件緩存,當組件切換時不會對當前組件進行卸載。
- 常用的兩個屬性 include/exclude,允許組件有條件的進行緩存。
- 兩個生命周期 activated/deactivated,用來得知當前組件是否處於活躍狀態。
- keep-alive 的中還運用了 LRU(最近最少使用) 算法,選擇最近最久未使用的組件予以淘汰。
Vue.extend 作用和原理
官方解釋:Vue.extend 使用基礎 Vue 構造器,創建一個“子類”。參數是一個包含組件選項的對象。
其實就是一個子類構造器 是 Vue 組件的核心 api 實現思路就是使用原型繼承的方法返回了 Vue 的子類 並且利用 mergeOptions 把傳入組件的 options 和父類的 options 進行了合並
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:
computed
是計算屬性,也就是計算值,它更多用於計算值的場景computed
具有緩存性,computed的值在getter執行后是會緩存的,只有在它依賴的屬性值改變之后,下一次獲取computed的值時才會重新調用對應的getter來計算computed
適用於計算比較消耗性能的計算場景
watch:
- 更多的是「觀察」的作用,類似於某些數據的監聽回調,用於觀察
props
$emit
或者本組件的值,當數據變化時來執行回調進行后續操作 - 無緩存性,頁面重新渲染時值不變化也會執行
小結:
- 當我們要進行數值計算,而且依賴於其他數據,那么把這個數據設計為computed
- 如果你需要在某個數據變化時做一些事情,使用watch來觀察這個數據變化
虛擬DOM的優劣如何?
優點:
- 保證性能下限: 虛擬DOM可以經過diff找出最小差異,然后批量進行patch,這種操作雖然比不上手動優化,但是比起粗暴的DOM操作性能要好很多,因此虛擬DOM可以保證性能下限
- 無需手動操作DOM: 虛擬DOM的diff和patch都是在一次更新中自動進行的,我們無需手動操作DOM,極大提高開發效率
- 跨平台: 虛擬DOM本質上是JavaScript對象,而DOM與平台強相關,相比之下虛擬DOM可以進行更方便地跨平台操作,例如服務器渲染、移動端開發等等
缺點:
- 無法進行極致優化: 在一些性能要求極高的應用中虛擬DOM無法進行針對性的極致優化,比如VScode采用直接手動操作DOM的方式進行極端的性能優化
虛擬DOM實現原理?
- 虛擬DOM本質上是JavaScript對象,是對真實DOM的抽象
- 狀態變更時,記錄新樹和舊樹的差異
- 最后把差異更新到真正的dom中
Vue 初始化頁面閃動問題如何解決?
出現該問題是因為在 Vue 代碼尚未被解析之前,尚無法控制頁面中 DOM 的顯示,所以會看見模板字符串等代碼。
解決方案是,在 css 代碼中添加 v-cloak 規則,同時在待編譯的標簽上添加 v-cloak 屬性:
[v-cloak] { display: none; }
<div v-cloak>
{{ message }}
</div>
Vue-router 路由有哪些模式?
一般有兩種模式:
(1)hash 模式:后面的 hash 值的變化,瀏覽器既不會向服務器發出請求,瀏覽器也不會刷新,每次 hash 值的變化會觸發 hashchange 事件。
(2)history 模式:利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。這兩個方法應用於瀏覽器的歷史記錄棧,在當前已有的 back、forward、go 的基礎之上,它們提供了對歷史記錄進行修改的功能。只是當它們執行修改時,雖然改變了當前的 URL,但瀏覽器不會立即向后端發送請求。
$nextTick 是什么?
Vue 實現響應式並不是在數據發生后立即更新 DOM,使用 vm.$nextTick
是在下次 DOM 更新循環結束之后立即執行延遲回調。在修改數據之后使用,則可以在回調中獲取更新后的 DOM。
Vue 中 computed 和 watch 有什么區別?
計算屬性 computed:
(1)支持緩存,只有依賴數據發生變化時,才會重新進行計算函數;
(2)計算屬性內不支持異步操作;
(3)計算屬性的函數中都有一個 get(默認具有,獲取計算屬性)和 set(手動添加,設置計算屬性)方法;
(4)計算屬性是自動監聽依賴值的變化,從而動態返回內容。
偵聽屬性 watch:
(1)不支持緩存,只要數據發生變化,就會執行偵聽函數;
(2)偵聽屬性內支持異步操作;
(3)偵聽屬性的值可以是一個對象,接收 handler 回調,deep,immediate 三個屬性;
(3)監聽是一個過程,在監聽的值變化時,可以觸發一個回調,並做一些其他事情。
action 與 mutation 的區別
mutation
是同步更新,$watch
嚴格模式下會報錯action
是異步操作,可以獲取數據后調用mutation
提交最終數據
談談對keep-alive的了解
keep-alive 可以實現組件的緩存,當組件切換時不會對當前組件進行卸載。常用的2個屬性
include/exclude ,2個生命周期
activated ,
deactivated
Vue 模板編譯原理
Vue 的編譯過程就是將 template 轉化為 render 函數的過程 分為以下三步
第一步是將 模板字符串 轉換成 element ASTs(解析器)
第二步是對 AST 進行靜態節點標記,主要用來做虛擬DOM的渲染優化(優化器)
第三步是 使用 element ASTs 生成 render 函數代碼字符串(代碼生成器)
Vue 修飾符有哪些
事件修飾符
- .stop 阻止事件繼續傳播
- .prevent 阻止標簽默認行為
- .capture 使用事件捕獲模式,即元素自身觸發的事件先在此處處理,然后才交由內部元素進行處理
- .self 只當在 event.target 是當前元素自身時觸發處理函數
- .once 事件將只會觸發一次
- .passive 告訴瀏覽器你不想阻止事件的默認行為
v-model 的修飾符
- .lazy 通過這個修飾符,轉變為在 change 事件再同步
- .number 自動將用戶的輸入值轉化為數值類型
- .trim 自動過濾用戶輸入的首尾空格
鍵盤事件的修飾符
- .enter
- .tab
- .delete (捕獲“刪除”和“退格”鍵)
- .esc
- .space
- .up
- .down
- .left
- .right
系統修飾鍵
- .ctrl
- .alt
- .shift
- .meta
鼠標按鈕修飾符
- .left
- .right
- .middle
Vue性能優化
編碼優化:
- 事件代理
keep-alive
- 拆分組件
key
保證唯一性- 路由懶加載、異步組件
- 防抖節流
Vue加載性能優化
- 第三方模塊按需導入(
babel-plugin-component
) - 圖片懶加載
用戶體驗
app-skeleton
骨架屏shellap
p殼pwa
SEO優化
- 預渲染