Vue3.0面試題

來,先介紹一下Vue的響應式系統

Vue爲MVVM框架,當數據模型data變化時,頁面視圖會獲得響應更新,其原理對data的getter/setter方法進行攔截(Object.defineProperty或者Proxy),利用發佈訂閱的設計模式,在getter方法中進行訂閱,在setter方法中發佈通知,讓全部訂閱者完成響應。vue

在響應式系統中,Vue會爲數據模型data的每個屬性新建一個訂閱中心做爲發佈者,而監聽器watch、計算屬性computed、視圖渲染template/render三個角色同時做爲訂閱者,對於監聽器watch,會直接訂閱觀察監聽的屬性,對於計算屬性computed和視圖渲染template/render,若是內部執行獲取了data的某個屬性,就會執行該屬性的getter方法,而後自動完成對該屬性的訂閱,當屬性被修改時,就會執行該屬性的setter方法,從而完成該屬性的發佈通知,通知全部訂閱者進行更新。node

computed與watch的區別

計算屬性computed和監聽器watch均可以觀察屬性的變化從而作出響應,不一樣的是:react

計算屬性computed更可能是做爲緩存功能的觀察者,它能夠將一個或者多個data的屬性進行復雜的計算生成一個新的值,提供給渲染函數使用,當依賴的屬性變化時,computed不會當即從新計算生成新的值,而是先標記爲髒數據,當下次computed被獲取時候,纔會進行從新計算並返回。webpack

而監聽器watch並不具有緩存性,監聽器watch提供一個監聽函數,當監聽的屬性發生變化時,會當即執行該函數。git

介紹一下Vue的生命週期

beforeCreate:是new Vue()以後觸發的第一個鉤子,在當前階段data、methods、computed以及watch上的數據和方法都不能被訪問。github

created:在實例建立完成後發生,當前階段已經完成了數據觀測,也就是可使用數據,更改數據,在這裏更改數據不會觸發updated函數。能夠作一些初始數據的獲取,在當前階段沒法與Dom進行交互,若是非要想,能夠經過vm.$nextTick來訪問Dom。web

beforeMount:發生在掛載以前,在這以前template模板已導入渲染函數編譯。而當前階段虛擬Dom已經建立完成,即將開始渲染。在此時也能夠對數據進行更改,不會觸發updated。正則表達式

mounted:在掛載完成後發生,在當前階段,真實的Dom掛載完畢,數據完成雙向綁定,能夠訪問到Dom節點,使用$refs屬性對Dom進行操做。算法

beforeUpdate:發生在更新以前,也就是響應式數據發生更新,虛擬dom從新渲染以前被觸發,你能夠在當前階段進行更改數據,不會形成重渲染。數據庫

updated:發生在更新完成以後,當前階段組件Dom已完成更新。要注意的是避免在此期間更改數據,由於這可能會致使無限循環的更新。

beforeDestroy:發生在實例銷燬以前,在當前階段實例徹底能夠被使用,咱們能夠在這時進行善後收尾工做,好比清除計時器。

destroyed:發生在實例銷燬以後,這個時候只剩下了dom空殼。組件已被拆解,數據綁定被卸除,監聽被移出,子實例也通通被銷燬。

爲何組件的data必須是一個函數

一個組件可能在不少地方使用,也就是會建立不少個實例,若是data是一個對象的話,對象是引用類型,一個實例修改了data會影響到其餘實例,因此data必須使用函數,爲每個實例建立一個屬於本身的data,使其同一個組件的不一樣實例互不影響。

組件之間是怎麼通訊的

  • 父子組件通訊

父組件 -> 子組件:prop

子組件 -> 父組件:$on/$emit

獲取組件實例:使用$parent/$children$refs.xxx,獲取到實例後直接獲取屬性數據或調用組件方法

  • 兄弟組件通訊

Event Bus:每個Vue實例都是一個Event Bus,都支持$on/$emit,能夠爲兄弟組件的實例之間new一個Vue實例,做爲Event Bus進行通訊。

Vuex:將狀態和方法提取到Vuex,完成共享

  • 跨級組件通訊

使用provide/inject

Event Bus:同兄弟組件Event Bus通訊

Vuex:將狀態和方法提取到Vuex,完成共享

Vue事件綁定原理說一下

每個Vue實例都是一個Event Bus,當子組件被建立的時候,父組件將事件傳遞給子組件,子組件初始化的時候是有$on方法將事件註冊到內部,在須要的時候使用$emit觸發函數,而對於原生native事件,使用addEventListener綁定到真實的DOM元素上。

slot是什麼?有什麼做用?原理是什麼?

slot又名插槽,是Vue的內容分發機制,組件內部的模板引擎使用slot元素做爲承載分發內容的出口。插槽slot是子組件的一個模板標籤元素,而這一個標籤元素是否顯示,以及怎麼顯示是由父組件決定的。

slot又分三類,默認插槽,具名插槽和做用域插槽。

  • 默認插槽:又名匿名查抄,當slot沒有指定name屬性值的時候一個默認顯示插槽,一個組件內只有有一個匿名插槽。
  • 具名插槽:帶有具體名字的插槽,也就是帶有name屬性的slot,一個組件能夠出現多個具名插槽。
  • 做用域插槽:默認插槽、具名插槽的一個變體,能夠是匿名插槽,也能夠是具名插槽,該插槽的不一樣點是在子組件渲染做用域插槽時,能夠將子組件內部的數據傳遞給父組件,讓父組件根據子組件的傳遞過來的數據決定如何渲染該插槽。

實現原理:當子組件vm實例化時,獲取到父組件傳入的slot標籤的內容,存放在vm.$slot中,默認插槽爲vm.$slot.default,具名插槽爲vm.$slot.xxx,xxx 爲插槽名,當組件執行渲染函數時候,遇到slot標籤,使用$slot中的內容進行替換,此時能夠爲插槽傳遞數據,若存在數據,則可稱該插槽爲做用域插槽。

Vue模板渲染的原理是什麼?

vue中的模板template沒法被瀏覽器解析並渲染,由於這不屬於瀏覽器的標準,不是正確的HTML語法,全部須要將template轉化成一個JavaScript函數,這樣瀏覽器就能夠執行這一個函數並渲染出對應的HTML元素,就可讓視圖跑起來了,這一個轉化的過程,就成爲模板編譯。

模板編譯又分三個階段,解析parse,優化optimize,生成generate,最終生成可執行函數render。

  • parse階段:使用大量的正則表達式對template字符串進行解析,將標籤、指令、屬性等轉化爲抽象語法樹AST。
  • optimize階段:遍歷AST,找到其中的一些靜態節點並進行標記,方便在頁面重渲染的時候進行diff比較時,直接跳過這一些靜態節點,優化runtime的性能。
  • generate階段:將最終的AST轉化爲render函數字符串。

template預編譯是什麼?

對於 Vue 組件來講,模板編譯只會在組件實例化的時候編譯一次,生成渲染函數以後在也不會進行編譯。所以,編譯對組件的 runtime 是一種性能損耗。

而模板編譯的目的僅僅是將template轉化爲render function,這個過程,正好能夠在項目構建的過程當中完成,這樣可讓實際組件在 runtime 時直接跳過模板渲染,進而提高性能,這個在項目構建的編譯template的過程,就是預編譯。

那template和jsx的有什麼分別?

對於 runtime 來講,只須要保證組件存在 render 函數便可,而咱們有了預編譯以後,咱們只須要保證構建過程當中生成 render 函數就能夠。

在 webpack 中,咱們使用vue-loader編譯.vue文件,內部依賴的vue-template-compiler模塊,在 webpack 構建過程當中,將template預編譯成 render 函數。

與 react 相似,在添加了jsx的語法糖解析器babel-plugin-transform-vue-jsx以後,就能夠直接手寫render函數。

因此,template和jsx的都是render的一種表現形式,不一樣的是:

JSX相對於template而言,具備更高的靈活性,在複雜的組件中,更具備優點,而 template 雖然顯得有些呆滯。可是 template 在代碼結構上更符合視圖與邏輯分離的習慣,更簡單、更直觀、更好維護。

說一下什麼是Virtual DOM

Virtual DOM 是 DOM 節點在 JavaScript 中的一種抽象數據結構,之因此須要虛擬DOM,是由於瀏覽器中操做DOM的代價比較昂貴,頻繁操做DOM會產生性能問題。虛擬DOM的做用是在每一次響應式數據發生變化引發頁面重渲染時,Vue對比更新先後的虛擬DOM,匹配找出儘量少的須要更新的真實DOM,從而達到提高性能的目的。

介紹一下Vue中的Diff算法

在新老虛擬DOM對比時

  • 首先,對比節點自己,判斷是否爲同一節點,若是不爲相同節點,則刪除該節點從新建立節點進行替換
  • 若是爲相同節點,進行patchVnode,判斷如何對該節點的子節點進行處理,先判斷一方有子節點一方沒有子節點的狀況(若是新的children沒有子節點,將舊的子節點移除)
  • 比較若是都有子節點,則進行updateChildren,判斷如何對這些新老節點的子節點進行操做(diff核心)。
  • 匹配時,找到相同的子節點,遞歸比較子節點

在diff中,只對同層的子節點進行比較,放棄跨級的節點比較,使得時間複雜從O(n^3)下降值O(n),也就是說,只有當新舊children都爲多個子節點時才須要用核心的Diff算法進行同層級比較。

key屬性的做用是什麼

在對節點進行diff的過程當中,判斷是否爲相同節點的一個很重要的條件是key是否相等,若是是相同節點,則會盡量的複用原有的DOM節點。因此key屬性是提供給框架在diff的時候使用的,而非開發者。

說說Vue2.0和Vue3.0有什麼區別

  1. 重構響應式系統,使用Proxy替換Object.defineProperty,使用Proxy優點:
  • 可直接監聽數組類型的數據變化
  • 監聽的目標爲對象自己,不須要像Object.defineProperty同樣遍歷每一個屬性,有必定的性能提高
  • 可攔截apply、ownKeys、has等13種方法,而Object.defineProperty不行
  • 直接實現對象屬性的新增/刪除
  1. 新增Composition API,更好的邏輯複用和代碼組織
  2. 重構 Virtual DOM
  • 模板編譯時的優化,將一些靜態節點編譯成常量
  • slot優化,將slot編譯爲lazy函數,將slot的渲染的決定權交給子組件
  • 模板中內聯事件的提取並重用(本來每次渲染都從新生成內聯函數)
  1. 代碼結構調整,更便於Tree shaking,使得體積更小
  2. 使用Typescript替換Flow

爲何要新增Composition API,它能解決什麼問題

Vue2.0中,隨着功能的增長,組件變得愈來愈複雜,愈來愈難維護,而難以維護的根本緣由是Vue的API設計迫使開發者使用watch,computed,methods選項組織代碼,而不是實際的業務邏輯。

另外Vue2.0缺乏一種較爲簡潔的低成本的機制來完成邏輯複用,雖然能夠minxis完成邏輯複用,可是當mixin變多的時候,會使得難以找到對應的data、computed或者method來源於哪一個mixin,使得類型推斷難以進行。

因此Composition API的出現,主要是也是爲了解決Option API帶來的問題,第一個是代碼組織問題,Compostion API可讓開發者根據業務邏輯組織本身的代碼,讓代碼具有更好的可讀性和可擴展性,也就是說當下一個開發者接觸這一段不是他本身寫的代碼時,他能夠更好的利用代碼的組織反推出實際的業務邏輯,或者根據業務邏輯更好的理解代碼。

第二個是實現代碼的邏輯提取與複用,固然mixin也能夠實現邏輯提取與複用,可是像前面所說的,多個mixin做用在同一個組件時,很難看出property是來源於哪一個mixin,來源不清楚,另外,多個mixin的property存在變量命名衝突的風險。而Composition API恰好解決了這兩個問題。

都說Composition API與React Hook很像,說說區別

從React Hook的實現角度看,React Hook是根據useState調用的順序來肯定下一次重渲染時的state是來源於哪一個useState,因此出現瞭如下限制

  • 不能在循環、條件、嵌套函數中調用Hook
  • 必須確保老是在你的React函數的頂層調用Hook
  • useEffect、useMemo等函數必須手動肯定依賴關係

而Composition API是基於Vue的響應式系統實現的,與React Hook的相比

  • 聲明在setup函數內,一次組件實例化只調用一次setup,而React Hook每次重渲染都須要調用Hook,使得React的GC比Vue更有壓力,性能也相對於Vue來講也較慢
  • Compositon API的調用不須要顧慮調用順序,也能夠在循環、條件、嵌套函數中使用
  • 響應式系統自動實現了依賴收集,進而組件的部分的性能優化由Vue內部本身完成,而React Hook須要手動傳入依賴,並且必須必須保證依賴的順序,讓useEffect、useMemo等函數正確的捕獲依賴變量,不然會因爲依賴不正確使得組件性能降低。

雖然Compositon API看起來比React Hook好用,可是其設計思想也是借鑑React Hook的。

SSR有了解嗎?原理是什麼?

在客戶端請求服務器的時候,服務器到數據庫中獲取到相關的數據,而且在服務器內部將Vue組件渲染成HTML,而且將數據、HTML一併返回給客戶端,這個在服務器將數據和組件轉化爲HTML的過程,叫作服務端渲染SSR。

而當客戶端拿到服務器渲染的HTML和數據以後,因爲數據已經有了,客戶端不須要再一次請求數據,而只須要將數據同步到組件或者Vuex內部便可。除了數據意外,HTML也結構已經有了,客戶端在渲染組件的時候,也只須要將HTML的DOM節點映射到Virtual DOM便可,不須要從新建立DOM節點,這個將數據和HTML同步的過程,又叫作客戶端激活。

使用SSR的好處:

  • 有利於SEO:其實就是有利於爬蟲來爬你的頁面,由於部分頁面爬蟲是不支持執行JavaScript的,這種不支持執行JavaScript的爬蟲抓取到的非SSR的頁面會是一個空的HTML頁面,而有了SSR之後,這些爬蟲就能夠獲取到完整的HTML結構的數據,進而收錄到搜索引擎中。
  • 白屏時間更短:相對於客戶端渲染,服務端渲染在瀏覽器請求URL以後已經獲得了一個帶有數據的HTML文本,瀏覽器只須要解析HTML,直接構建DOM樹就能夠。而客戶端渲染,須要先獲得一個空的HTML頁面,這個時候頁面已經進入白屏,以後還須要通過加載並執行 JavaScript、請求後端服務器獲取數據、JavaScript 渲染頁面幾個過程才能夠看到最後的頁面。特別是在複雜應用中,因爲須要加載 JavaScript 腳本,越是複雜的應用,須要加載的 JavaScript 腳本就越多、越大,這會致使應用的首屏加載時間很是長,進而下降了體驗感。

更多詳情查看 完全理解服務端渲染-SSR原理 https://github.com/yacan8/blo...

相關文章
相關標籤/搜索