vue面試題總結


1、如何理解MVVM開發模式?

MVVM分為Model、View、ViewModel三者。

Model:代表數據模型,數據和業務邏輯都在Model層中定義;
View:代表UI視圖,負責數據的展示;
ViewModel:負責監聽Model中數據的改變並且控制視圖的更新,處理用戶交互操作;

Model和View並無直接關聯,而是通過ViewModel來進行聯系的,Model和ViewModel之間有着雙向數據綁定的聯系。因此當Model中的數據改變時會觸發View層的刷新,View中由於用戶交互操作而改變的數據也會在Model中同步。

這種模式實現了Model和View的數據自動同步,因此開發者只需要專注對數據的維護操作即可,而不需要自己操作dom。

 

2、MVVM和MVC區別?和其他框架(jquery)區別?那些場景適用?

  MVVM和MVC都是一種設計思想,主要就是MVC中的Controller演變成ViewModel,,MVVM主要通過數據來顯示視圖層而不是操作節點,解決了MVC中大量的DOM操作使頁面渲染性能降低,加載速度慢,影響用戶體驗問題。主要用於數據操作比較多的場景。

  場景:數據操作比較多的場景,更加便

 

3、v-if 和 v-show 有什么區別

v-show 僅僅控制元素的顯示方式,將 display 屬性在 block 和 none 來回切換;而v-if會控制這個 DOM 節點的存在與否。當我們需要經常切換某個元素的顯示/隱藏時,使用v-show會更加節省性能上的開銷;當只需要一次顯示或隱藏時,使用v-if更加合理。

 

4、Vue的雙向數據綁定原理是什么?

  vue.js是采用數據劫持結合發布者 - 訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應的監聽回調。

 

5、簡述Vue的響應式原理

當一個Vue實例創建時,vue會遍歷data選項的屬性,用 Object.defineProperty 將它們轉為getter/setter並且在內部追蹤相關依賴,在屬性被訪問和修改時通知變化。
每個組件實例都有相應的watcher程序實例,它會在組件渲染的過程中把屬性記錄為依賴,之后當依賴項的setter被調用時,會通知watcher重新計算,從而致使它關聯的組件得以更新。

 

 

 

 

6、Vue.js的模板編譯的理解

簡而言之,就是先轉化成AST樹,再得到的渲染函數返回VNODE(Vue公司的虛擬DOM節點)


詳情步驟:
  首先,通過編譯編譯器把模板編譯成AST語法樹(抽象語法樹即源代碼的抽象語法結構的樹狀表現形式),編譯是createCompiler的返回值,createCompiler是用以創建編譯器的。負責合並選項。
  然后,AST會經過生成(將AST語法樹轉化成渲染功能字符串的過程)得到渲染函數,渲染的返回值是VNode,VNode是Vue的虛擬DOM節點,里面有(標簽名,子節點,文本等等)

 

7、vue中 key 值的作用

  key的作用主要是為了高效的更新虛擬DOM。

  key 是給每一個 vnode 的唯一 id,依靠 key,我們的 diff 操作可以更准確、更快速 (對於簡單列表頁渲染來說 diff 節點也更快,但會產生一些隱藏的副作用,比如可能不會產生過渡效果,或者在某些節點有綁定數據(表單)狀態,會出現狀態錯位。)
  diff 算法的過程中,先會進行新舊節點的首尾交叉對比,當無法匹配的時候會用新節點的 key 與舊節點進行比對,從而找到相應舊節點.

  更准確 : 因為帶 key 就不是就地復用了,在 sameNode 函數 a.key === b.key 對比中可以避免就地復用的情況。所以會更加准確,如果不加 key,會導致之前節點的狀態被保留下來,會產生一系列的 bug。
  更快速 : key 的唯一性可以被 Map 數據結構充分利用,相比於遍歷查找的時間復雜度 O(n),Map 的時間復雜度僅僅為 O(1)

 

8、vue-router有哪幾種導航鈎子?

  一種是全局導航鈎子:router.beforeEach(to,from,next)

  第二種:組件內的鈎子beforeRouteEnter (to, from, nextbeforeRouteUpdate (to, from, nextbeforeRouteLeave (to, from, next)

  第三種:單獨路由獨享組件 beforeEnter: (to, from, next)

 

9、$route和$router的區別

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

 

10、Vue中給data中的對象屬性添加一個新的屬性時會發生什么,如何解決?

  可以成功添加,但是視圖並未刷新,原因在於在Vue實例創建時, obj.b 並未聲明,因此就沒有被Vue轉換為響應式的屬性,自然就不會觸發視圖的更新,這時就需要使用Vue的全局api—— $set()。

   this.$set(this.obj, 'b', 'obj.b')  $set() 方法相當於手動的去把 obj.b 處理成一個響應式的屬性,此時視圖也會跟着改變了

 

 11、computed 和 watch 有什么區別及運用場景?

區別:

  computed 計算屬性 : 依賴其它屬性值,並且 computed 的值有緩存,只有它依賴的屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值。
  watch 偵聽器 : 更多的是「觀察」的作用,無緩存性,類似於某些數據的監聽回調,每當監聽的數據變化時都會執行回調進行后續操作。

運用場景:

  當我們需要進行數值計算,並且依賴於其它數據時,應該使用 computed,因為可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算。
  當我們需要在數據變化時執行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行異步操作 ( 訪問一個 API ),限制我們執行該操作的頻率,並在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。

 

12、computed 的實現原理

computed 本質是一個惰性求值的觀察者。

computed 內部實現了一個惰性的 watcher,也就是 computed watcher,computed watcher 不會立刻求值,同時持有一個 dep 實例。

其內部通過 this.dirty 屬性標記計算屬性是否需要重新求值。

當 computed 的依賴狀態發生改變時,就會通知這個惰性的 watcher,

computed watcher 通過 this.dep.subs.length 判斷有沒有訂閱者,

有的話,會重新計算,然后對比新舊值,如果變化了,會重新渲染。 (Vue 想確保不僅僅是計算屬性依賴的值發生變化,而是當計算屬性最終計算的值發生變化時才會觸發渲染 watcher 重新渲染,本質上是一種優化。)

沒有的話,僅僅把 this.dirty = true。 (當計算屬性依賴於其他數據時,屬性並不會立即重新計算,只有之后其他地方需要讀取屬性的時候,它才會真正計算,即具備 lazy(懶計算)特性。)

 

13、vue 的 nextTick 方法的實現原理

  vue 用異步隊列的方式來控制 DOM 更新和 nextTick 回調先后執行
  microtask 因為其高優先級特性,能確保隊列中的微任務在一次事件循環前被執行完畢

 

14、Vue 組件 data 為什么必須是函數 ?

  因為組件是可以復用的,JS 里對象是引用關系,如果組件 data 是一個對象,那么子組件中的 data 屬性值會互相污染。
  所以一個組件的 data 選項必須是一個函數,因此每個實例可以維護一份被返回對象的獨立的拷貝。new Vue 的實例是不會被復用的,因此不存在以上問題。

 

15、說說 Vue 的渲染過程

 

 

  調用 compile 函數,生成 render 函數字符串 ,編譯過程如下:
  parse 函數解析 template,生成 ast(抽象語法樹)
  optimize 函數優化靜態節點 (標記不需要每次都更新的內容,diff 算法會直接跳過靜態節點,從而減少比較的過程,優化了 patch 的性能)
  generate 函數生成 render 函數字符串
  調用 new Watcher 函數,監聽數據的變化,當數據發生變化時,Render 函數執行生成 vnode 對象
  調用 patch 方法,對比新舊 vnode 對象,通過 DOM diff 算法,添加、修改、刪除真正的 DOM 元素

 

16、為什么在 Vue3.0 采用了 Proxy,拋棄了 Object.defineProperty?

Object.defineProperty無法監控到數組下標的變化,導致通過數組下標添加元素,不能實時響應;

Object.defineProperty只能劫持對象的屬性,從而需要對每個對象,每個屬性進行遍歷,如果,屬性值是對象,還需要深度遍歷。

Proxy可以劫持整個對象,並返回一個新的對象。

Proxy不僅可以代理對象,還可以代理數組。還可以代理動態增加的屬性。

 

17、v-if和v-for一起使用的弊端及解決辦法

  由於v-for的優先級比v-if高,所以導致每循環一次就會去v-if一次,而v-if是通過創建和銷毀dom元素來控制元素的顯示與隱藏,所以就會不停的去創建和銷毀元素,造成頁面卡頓,性能下降。

解決辦法:
  1.在v-for的外層或內層包裹一個元素來使用v-if
  2.用computed處理

 

18、組件傳值方式有哪些

  父傳子:子組件通過props['xx'] 來接收父組件傳遞的屬性 xx 的值

  子傳父:子組件通過 this.$emit('fnName',value) 來傳遞,父組件通過接收 fnName 事件方法來接收回調

  其他方式:通過創建一個bus,進行傳值

  // 創建一個文件,定義bus中間件,並導出

// 創建一個文件,定義bus中間件,並導出
const bus = new Vue()
// 在一個組件中發送事件
bus.$emit('事件名稱', 傳遞的參數)
// 在另一個組件中監聽事件
bus.$on('事件名稱', 得到傳過來的參數)

 

 19、Virtual DOM 是什么?

 

我們先對上圖幾個概念加以解釋:

  • 渲染函數:渲染函數是用來生成Virtual DOM的。Vue推薦使用模板來構建我們的應用界面,在底層實現中Vue會將模板編譯成渲染函數,當然我們也可以不寫模板,直接寫渲染函數,以獲得更好的控制。
  • VNode 虛擬節點:它可以代表一個真實的 dom 節點。通過 createElement 方法能將 VNode 渲染成 dom 節點。簡單地說,vnode可以理解成節點描述對象,它描述了應該怎樣去創建真實的DOM節點。
  • patch(也叫做patching算法):虛擬DOM最核心的部分,它可以將vnode渲染成真實的DOM,這個過程是對比新舊虛擬節點之間有哪些不同,然后根據對比結果找出需要更新的的節點進行更新。這點我們從單詞含義就可以看出, patch本身就有補丁、修補的意思,其實際作用是在現有DOM上進行修改來實現更新視圖的目的。Vue的Virtual DOM Patching算法是基於Snabbdom的實現,並在些基礎上作了很多的調整和改進。

 

  Virtual DOM 其實就是一棵以 JavaScript 對象( VNode 節點)作為基礎的樹,用對象屬性來描述節點,實際上它只是一層對真實 DOM 的抽象。最終可以通過一系列操作使這棵樹映射到真實環境上。

  簡單來說,可以把Virtual DOM 理解為一個簡單的JS對象,並且最少包含標簽名( tag)、屬性(attrs)和子元素對象( children)三個屬性。不同的框架對這三個屬性的命名會有點差別。

 

20、Virtual DOM 作用是什么?

  虛擬DOM的最終目標是將虛擬節點渲染到視圖上。但是如果直接使用虛擬節點覆蓋舊節點的話,會有很多不必要的DOM操作。例如,一個ul標簽下很多個li標簽,其中只有一個li有變化,這種情況下如果使用新的ul去替代舊的ul,因為這些不必要的DOM操作而造成了性能上的浪費。

為了避免不必要的DOM操作,虛擬DOM在虛擬節點映射到視圖的過程中,將虛擬節點與上一次渲染視圖所使用的舊虛擬節點(oldVnode)做對比,找出真正需要更新的節點來進行DOM操作,從而避免操作其他無需改動的DOM。

  其實虛擬DOM在Vue.js主要做了兩件事:

  • 提供與真實DOM節點所對應的虛擬節點vnode
  • 將虛擬節點vnode和舊虛擬節點oldVnode進行對比,然后更新視圖

 

21、為何需要Virtual DOM?

  • 具備跨平台的優勢

  由於 Virtual DOM 是以 JavaScript 對象為基礎而不依賴真實平台環境,所以使它具有了跨平台的能力,比如說瀏覽器平台、Weex、Node 等。

  • 操作 DOM 慢,js運行效率高。我們可以將DOM對比操作放在JS層,提高效率。

  因為DOM操作的執行速度遠不如Javascript的運算速度快,因此,把大量的DOM操作搬運到Javascript中,運用patching算法來計算出真正需要更新的節點,最大限度地減少DOM操作,從而顯著提高性能。

Virtual DOM 本質上就是在 JS 和 DOM 之間做了一個緩存。可以類比 CPU 和硬盤,既然硬盤這么慢,我們就在它們之間加個緩存:既然 DOM 這么慢,我們就在它們 JS 和 DOM 之間加個緩存。CPU(JS)只操作內存(Virtual DOM),最后的時候再把變更寫入硬盤(DOM)

  • 提升渲染性能

  Virtual DOM的優勢不在於單次的操作,而是在大量、頻繁的數據更新下,能夠對視圖進行合理、高效的更新。

 

22、談談diff 算法

  為了實現高效的DOM操作,一套高效的虛擬DOM diff算法顯得很有必要。我們通過patch 的核心----diff 算法,找出本次DOM需要更新的節點來更新,其他的不更新。比如修改某個model 100次,從1加到100,那么有了Virtual DOM的緩存之后,只會把最后一次修改patch到view上。那diff 算法的實現過程是怎樣的?

  

 

 

 

Vue的diff算法是基於snabbdom改造過來的,僅在同級的vnode間做diff,遞歸地進行同級vnode的diff,最終實現整個DOM樹的更新。因為跨層級的操作是非常少的,忽略不計,這樣時間復雜度就從O(n3)變成O(n)。

diff 算法包括幾個步驟:

  • 用 JavaScript 對象結構表示 DOM 樹的結構;然后用這個樹構建一個真正的 DOM 樹,插到文檔當中
  • 當狀態變更的時候,重新構造一棵新的對象樹。然后用新的樹和舊的樹進行比較,記錄兩棵樹差異
  • 把所記錄的差異應用到所構建的真正的DOM樹上,視圖就更新了

 


免責聲明!

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



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