本篇文章給大家總結一些值得收藏的2022年精選vue高頻面試題(附答案)。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。
Vue-router 導航守衛(wèi)有哪些
- 全局前置/鉤子:beforeEach、beforeResolve、afterEach
- 路由獨享的守衛(wèi):beforeEnter
- 組件內(nèi)的守衛(wèi):beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
(學習視頻分享:vue視頻教程)
為什么在 Vue3.0 采用了 Proxy,拋棄了 Object.defineProperty?
Object.defineProperty 本身有一定的監(jiān)控到數(shù)組下標變化的能力,但是在 Vue 中,從性能/體驗的性價比考慮,尤大大就棄用了這個特性(Vue 為什么不能檢測數(shù)組變動 )。為了解決這個問題,經(jīng)過 vue 內(nèi)部處理后可以使用以下幾種方法來監(jiān)聽數(shù)組
push(); pop(); shift(); unshift(); splice(); sort(); reverse();
由于只針對了以上 7 種方法進行了 hack 處理,所以其他數(shù)組的屬性也是檢測不到的,還是具有一定的局限性。
Object.defineProperty 只能劫持對象的屬性,因此我們需要對每個對象的每個屬性進行遍歷。Vue 2.x 里,是通過 遞歸 + 遍歷 data 對象來實現(xiàn)對數(shù)據(jù)的監(jiān)控的,如果屬性值也是對象那么需要深度遍歷,顯然如果能劫持一個完整的對象是才是更好的選擇。
Proxy 可以劫持整個對象,并返回一個新的對象。Proxy 不僅可以代理對象,還可以代理數(shù)組。還可以代理動態(tài)增加的屬性。
v-for 為什么要加 key
如果不使用 key,Vue 會使用一種最大限度減少動態(tài)元素并且盡可能的嘗試就地修改/復用相同類型元素的算法。key 是為 Vue 中 vnode 的唯一標記,通過這個 key,我們的 diff 操作可以更準確、更快速
-
更準確:因為帶 key 就不是就地復用了,在 sameNode 函數(shù) a.key === b.key 對比中可以避免就地復用的情況。所以會更加準確。
-
更快速:利用 key 的唯一性生成 map 對象來獲取對應節(jié)點,比遍歷方式更快
如何從真實DOM到虛擬DOM
涉及到Vue中的模板編譯原理,主要過程:
-
將模板轉(zhuǎn)換成
ast
樹,ast
用對象來描述真實的JS語法(將真實DOM轉(zhuǎn)換成虛擬DOM) -
優(yōu)化樹
-
將
ast
樹生成代碼
為什么Vue采用異步渲染呢?
Vue
是組件級更新,如果不采用異步更新,那么每次更新數(shù)據(jù)都會對當前組件進行重新渲染,所以為了性能, Vue
會在本輪數(shù)據(jù)更新后,在異步更新視圖。核心思想 nextTick
。
dep.notify()
通知 watcher進行更新, subs[i].update
依次調(diào)用 watcher 的 update
, queueWatcher
將watcher 去重放入隊列, nextTick( flushSchedulerQueue
)在下一tick中刷新watcher隊列(異步)。
為什么vue組件中data必須是一個函數(shù)?
對象為引用類型,當復用組件時,由于數(shù)據(jù)對象都指向同一個data對象,當在一個組件中修改data時,其他重用的組件中的data會同時被修改;而使用返回對象的函數(shù),由于每次返回的都是一個新對象(Object的實例),引用地址不同,則不會出現(xiàn)這個問題。
MVC 和 MVVM 區(qū)別
MVC
MVC 全名是 Model View Controller,是模型(model)-視圖(view)-控制器(controller)的縮寫,一種軟件設計典范
- Model(模型):是應用程序中用于處理應用程序數(shù)據(jù)邏輯的部分。通常模型對象負責在數(shù)據(jù)庫中存取數(shù)據(jù)
- View(視圖):是應用程序中處理數(shù)據(jù)顯示的部分。通常視圖是依據(jù)模型數(shù)據(jù)創(chuàng)建的
- Controller(控制器):是應用程序中處理用戶交互的部分。通??刂破髫撠煆囊晥D讀取數(shù)據(jù),控制用戶輸入,并向模型發(fā)送數(shù)據(jù)
MVC 的思想:一句話描述就是 Controller 負責將 Model 的數(shù)據(jù)用 View 顯示出來,換句話說就是在 Controller 里面把 Model 的數(shù)據(jù)賦值給 View。
MVVM
MVVM 新增了 VM 類
- ViewModel 層:做了兩件事達到了數(shù)據(jù)的雙向綁定 一是將【模型】轉(zhuǎn)化成【視圖】,即將后端傳遞的數(shù)據(jù)轉(zhuǎn)化成所看到的頁面。實現(xiàn)的方式是:數(shù)據(jù)綁定。二是將【視圖】轉(zhuǎn)化成【模型】,即將所看到的頁面轉(zhuǎn)化成后端的數(shù)據(jù)。實現(xiàn)的方式是:DOM 事件監(jiān)聽。
MVVM 與 MVC 最大的區(qū)別就是:它實現(xiàn)了 View 和 Model 的自動同步,也就是當 Model 的屬性改變時,我們不用再自己手動操作 Dom 元素,來改變 View 的顯示,而是改變屬性后該屬性對應 View 層顯示會自動改變(對應Vue數(shù)據(jù)驅(qū)動的思想)
整體看來,MVVM 比 MVC 精簡很多,不僅簡化了業(yè)務與界面的依賴,還解決了數(shù)據(jù)頻繁更新的問題,不用再用選擇器操作 DOM 元素。因為在 MVVM 中,View 不知道 Model 的存在,Model 和 ViewModel 也觀察不到 View,這種低耦合模式提高代碼的可重用性
注意:Vue 并沒有完全遵循 MVVM 的思想 這一點官網(wǎng)自己也有說明
那么問題來了 為什么官方要說 Vue 沒有完全遵循 MVVM 思想呢?
- 嚴格的 MVVM 要求 View 不能和 Model 直接通信,而 Vue 提供了$refs 這個屬性,讓 Model 可以直接操作 View,違反了這一規(guī)定,所以說 Vue 沒有完全遵循 MVVM。
Vue 為什么要用 vm.$set() 解決對象新增屬性不能響應的問題 ?你能說說如下代碼的實現(xiàn)原理么?
1)Vue為什么要用vm.$set() 解決對象新增屬性不能響應的問題
-
Vue使用了Object.defineProperty實現(xiàn)雙向數(shù)據(jù)綁定
-
在初始化實例時對屬性執(zhí)行 getter/setter 轉(zhuǎn)化
-
屬性必須在data對象上存在才能讓Vue將它轉(zhuǎn)換為響應式的(這也就造成了Vue無法檢測到對象屬性的添加或刪除)
所以Vue提供了Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)
2)接下來我們看看框架本身是如何實現(xiàn)的呢?
Vue 源碼位置:vue/src/core/instance/index.js
export function set (target: Array<any> | Object, key: any, val: any): any { // target 為數(shù)組 if (Array.isArray(target) && isValidArrayIndex(key)) { // 修改數(shù)組的長度, 避免索引>數(shù)組長度導致splcie()執(zhí)行有誤 target.length = Math.max(target.length, key) // 利用數(shù)組的splice變異方法觸發(fā)響應式 target.splice(key, 1, val) return val } // key 已經(jīng)存在,直接修改屬性值 if (key in target && !(key in Object.prototype)) { target[key] = val return val } const ob = (target: any).__ob__ // target 本身就不是響應式數(shù)據(jù), 直接賦值 if (!ob) { target[key] = val return val } // 對屬性進行響應式處理 defineReactive(ob.value, key, val) ob.dep.notify() return val }
我們閱讀以上源碼可知,vm.$set 的實現(xiàn)原理是:
-
如果目標是數(shù)組,直接使用數(shù)組的 splice 方法觸發(fā)相應式;
-
如果目標是對象,會先判讀屬性是否存在、對象是否是響應式,
-
最終如果要對屬性進行響應式處理,則是通過調(diào)用 defineReactive 方法進行響應式處理
defineReactive 方法就是 Vue 在初始化對象時,給對象屬性采用 Object.defineProperty 動態(tài)添加 getter 和 setter 的功能所調(diào)用的方法
Vue3.0 和 2.0 的響應式原理區(qū)別
Vue3.x 改用 Proxy 替代 Object.defineProperty。因為 Proxy 可以直接監(jiān)聽對象和數(shù)組的變化,并且有多達 13 種攔截方法。
相關代碼如下
import { mutableHandlers } from "./baseHandlers"; // 代理相關邏輯 import { isObject } from "./util"; // 工具方法 export function reactive(target) { // 根據(jù)不同參數(shù)創(chuàng)建不同響應式對象 return createReactiveObject(target, mutableHandlers); } function createReactiveObject(target, baseHandler) { if (!isObject(target)) { return target; } const observed = new Proxy(target, baseHandler); return observed; } const get = createGetter(); const set = createSetter(); function createGetter() { return function get(target, key, receiver) { // 對獲取的值進行放射 const res = Reflect.get(target, key, receiver); console.log("屬性獲取", key); if (isObject(res)) { // 如果獲取的值是對象類型,則返回當前對象的代理對象 return reactive(res); } return res; }; } function createSetter() { return function set(target, key, value, receiver) { const oldValue = target[key]; const hadKey = hasOwn(target, key); const result = Reflect.set(target, key, value, receiver); if (!hadKey) { console.log("屬性新增", key, value); } else if (hasChanged(value, oldValue)) { console.log("屬性值被修改", key, value); } return result; }; } export const mutableHandlers = { get, // 當獲取屬性時調(diào)用此方法 set, // 當修改屬性時調(diào)用此方法 };
Vue模版編譯原理知道嗎,能簡單說一下嗎?
簡單說,Vue的編譯過程就是將template
轉(zhuǎn)化為render
函數(shù)的過程。會經(jīng)歷以下階段:
- 生成AST樹
- 優(yōu)化
- codegen
首先解析模版,生成AST語法樹
(一種用JavaScript對象的形式來描述整個模板)。 使用大量的正則表達式對模板進行解析,遇到標簽、文本的時候都會執(zhí)行對應的鉤子進行相關處理。
Vue的數(shù)據(jù)是響應式的,但其實模板中并不是所有的數(shù)據(jù)都是響應式的。有一些數(shù)據(jù)首次渲染后就不會再變化,對應的DOM也不會變化。那么優(yōu)化過程就是深度遍歷AST樹,按照相關條件對樹節(jié)點進行標記。這些被標記的節(jié)點(靜態(tài)節(jié)點)我們就可以跳過對它們的比對
,對運行時的模板起到很大的優(yōu)化作用。
編譯的最后一步是將優(yōu)化后的AST樹轉(zhuǎn)換為可執(zhí)行的代碼
。
MVVM的優(yōu)缺點?
優(yōu)點:
- 分離視圖(View)和模型(Model),降低代碼耦合,提?視圖或者邏輯的重?性: ?如視圖(View)可以獨?于Model變化和修改,?個ViewModel可以綁定不同的"View"上,當View變化的時候Model不可以不變,當Model變化的時候View也可以不變。你可以把?些視圖邏輯放在?個ViewModel??,讓很多view重?這段視圖邏輯
- 提?可測試性: ViewModel的存在可以幫助開發(fā)者更好地編寫測試代碼
- ?動更新dom: 利?雙向綁定,數(shù)據(jù)更新后視圖?動更新,讓開發(fā)者從繁瑣的?動dom中解放
缺點:
- Bug很難被調(diào)試: 因為使?雙向綁定的模式,當你看到界?異常了,有可能是你View的代碼有Bug,也可能是Model的代碼有問題。數(shù)據(jù)綁定使得?個位置的Bug被快速傳遞到別的位置,要定位原始出問題的地?就變得不那么容易了。另外,數(shù)據(jù)綁定的聲明是指令式地寫在View的模版當中的,這些內(nèi)容是沒辦法去打斷點debug的
- ?個?的模塊中model也會很?,雖然使??便了也很容易保證了數(shù)據(jù)的?致性,當時?期持有,不釋放內(nèi)存就造成了花費