本文小編為大家詳細介紹“vue高頻面試題實例分析”,內容詳細,步驟清晰,細節處理妥當,希望這篇“vue高頻面試題實例分析”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
成都創新互聯公司是一家集網站建設,宿州企業網站建設,宿州品牌網站建設,網站定制,宿州網站建設報價,網絡營銷,網絡優化,宿州網站推廣為一體的創新建站企業,幫助傳統企業提升企業形象加強企業競爭力。可充分滿足這一群體相比中小企業更為豐富、高端、多元的互聯網需求。同時我們時刻保持專業、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們為更多的企業打造出實用型網站。
全局前置/鉤子:beforeEach、beforeResolve、afterEach
路由獨享的守衛:beforeEnter
組件內的守衛:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
Object.defineProperty 本身有一定的監控到數組下標變化的能力,但是在 Vue 中,從性能/體驗的性價比考慮,尤大大就棄用了這個特性(Vue 為什么不能檢測數組變動 )。為了解決這個問題,經過 vue 內部處理后可以使用以下幾種方法來監聽數組
push(); pop(); shift(); unshift(); splice(); sort(); reverse();
由于只針對了以上 7 種方法進行了 hack 處理,所以其他數組的屬性也是檢測不到的,還是具有一定的局限性。
Object.defineProperty 只能劫持對象的屬性,因此我們需要對每個對象的每個屬性進行遍歷。Vue 2.x 里,是通過 遞歸 + 遍歷 data 對象來實現對數據的監控的,如果屬性值也是對象那么需要深度遍歷,顯然如果能劫持一個完整的對象是才是更好的選擇。
Proxy 可以劫持整個對象,并返回一個新的對象。Proxy 不僅可以代理對象,還可以代理數組。還可以代理動態增加的屬性。
如果不使用 key,Vue 會使用一種最大限度減少動態元素并且盡可能的嘗試就地修改/復用相同類型元素的算法。key 是為 Vue 中 vnode 的唯一標記,通過這個 key,我們的 diff 操作可以更準確、更快速
更準確:因為帶 key 就不是就地復用了,在 sameNode 函數 a.key === b.key 對比中可以避免就地復用的情況。所以會更加準確。
更快速:利用 key 的唯一性生成 map 對象來獲取對應節點,比遍歷方式更快
涉及到Vue中的模板編譯原理,主要過程:
將模板轉換成 ast
樹, ast
用對象來描述真實的JS語法(將真實DOM轉換成虛擬DOM)
優化樹
將 ast
樹生成代碼
Vue
是組件級更新,如果不采用異步更新,那么每次更新數據都會對當前組件進行重新渲染,所以為了性能, Vue
會在本輪數據更新后,在異步更新視圖。核心思想 nextTick
。
dep.notify()
通知 watcher進行更新, subs[i].update
依次調用 watcher 的 update
, queueWatcher
將watcher 去重放入隊列, nextTick( flushSchedulerQueue
)在下一tick中刷新watcher隊列(異步)。
對象為引用類型,當復用組件時,由于數據對象都指向同一個data對象,當在一個組件中修改data時,其他重用的組件中的data會同時被修改;而使用返回對象的函數,由于每次返回的都是一個新對象(Object的實例),引用地址不同,則不會出現這個問題。
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。
1)Vue為什么要用vm.$set() 解決對象新增屬性不能響應的問題
Vue使用了Object.defineProperty實現雙向數據綁定
在初始化實例時對屬性執行 getter/setter 轉化
屬性必須在data對象上存在才能讓Vue將它轉換為響應式的(這也就造成了Vue無法檢測到對象屬性的添加或刪除)
所以Vue提供了Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)
2)接下來我們看看框架本身是如何實現的呢?
Vue 源碼位置:vue/src/core/instance/index.js
export function set (target: Array<any> | Object, key: any, val: any): any { // target 為數組 if (Array.isArray(target) && isValidArrayIndex(key)) { // 修改數組的長度, 避免索引>數組長度導致splcie()執行有誤 target.length = Math.max(target.length, key) // 利用數組的splice變異方法觸發響應式 target.splice(key, 1, val) return val } // key 已經存在,直接修改屬性值 if (key in target && !(key in Object.prototype)) { target[key] = val return val } const ob = (target: any).__ob__ // target 本身就不是響應式數據, 直接賦值 if (!ob) { target[key] = val return val } // 對屬性進行響應式處理 defineReactive(ob.value, key, val) ob.dep.notify() return val }
我們閱讀以上源碼可知,vm.$set 的實現原理是:
如果目標是數組,直接使用數組的 splice 方法觸發相應式;
如果目標是對象,會先判讀屬性是否存在、對象是否是響應式,
最終如果要對屬性進行響應式處理,則是通過調用 defineReactive 方法進行響應式處理
defineReactive 方法就是 Vue 在初始化對象時,給對象屬性采用 Object.defineProperty 動態添加 getter 和 setter 的功能所調用的方法
Vue3.x 改用 Proxy 替代 Object.defineProperty。因為 Proxy 可以直接監聽對象和數組的變化,并且有多達 13 種攔截方法。
相關代碼如下
import { mutableHandlers } from "./baseHandlers"; // 代理相關邏輯 import { isObject } from "./util"; // 工具方法 export function reactive(target) { // 根據不同參數創建不同響應式對象 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, // 當獲取屬性時調用此方法 set, // 當修改屬性時調用此方法 };
簡單說,Vue的編譯過程就是將template
轉化為render
函數的過程。會經歷以下階段:
生成AST樹
優化
codegen
首先解析模版,生成AST語法樹
(一種用JavaScript對象的形式來描述整個模板)。 使用大量的正則表達式對模板進行解析,遇到標簽、文本的時候都會執行對應的鉤子進行相關處理。
Vue的數據是響應式的,但其實模板中并不是所有的數據都是響應式的。有一些數據首次渲染后就不會再變化,對應的DOM也不會變化。那么優化過程就是深度遍歷AST樹,按照相關條件對樹節點進行標記。這些被標記的節點(靜態節點)我們就可以跳過對它們的比對
,對運行時的模板起到很大的優化作用。
編譯的最后一步是將優化后的AST樹轉換為可執行的代碼
。
優點:
分離視圖(View)和模型(Model),降低代碼耦合,提?視圖或者邏輯的重?性: ?如視圖(View)可以獨?于Model變化和修改,?個ViewModel可以綁定不同的"View"上,當View變化的時候Model不可以不變,當Model變化的時候View也可以不變。你可以把?些視圖邏輯放在?個ViewModel??,讓很多view重?這段視圖邏輯
提?可測試性: ViewModel的存在可以幫助開發者更好地編寫測試代碼
?動更新dom: 利?雙向綁定,數據更新后視圖?動更新,讓開發者從繁瑣的?動dom中解放
缺點:
Bug很難被調試: 因為使?雙向綁定的模式,當你看到界?異常了,有可能是你View的代碼有Bug,也可能是Model的代碼有問題。數據綁定使得?個位置的Bug被快速傳遞到別的位置,要定位原始出問題的地?就變得不那么容易了。另外,數據綁定的聲明是指令式地寫在View的模版當中的,這些內容是沒辦法去打斷點debug的
?個?的模塊中model也會很?,雖然使??便了也很容易保證了數據的?致性,當時?期持有,不釋放內存就造成了花費更多的內存
對于?型的圖形應?程序,視圖狀態較多,ViewModel的構建和維護的成本都會?較?。
不會立即同步執行重新渲染。Vue 實現響應式并不是數據發生變化之后 DOM 立即變化,而是按一定的策略進行 DOM 的更新。Vue 在更新 DOM 時是異步執行的。只要偵聽到數據變化, Vue 將開啟一個隊列,并緩沖在同一事件循環中發生的所有數據變更。
如果同一個watcher被多次觸發,只會被推入到隊列中一次。這種在緩沖時去除重復數據對于避免不必要的計算和 DOM 操作是非常重要的。然后,在下一個的事件循環tick中,Vue 刷新隊列并執行實際(已去重的)工作。
時間復雜度:個樹的完全 diff
算法是一個時間復雜度為 O(n*3)
,vue進行優化轉化成 O(n)
。
理解:
最小量更新, key
很重要。這個可以是這個節點的唯一標識,告訴 diff
算法,在更改前后它們是同一個DOM節點
擴展 v-for
為什么要有 key
,沒有 key
會暴力復用,舉例子的話隨便說一個比如移動節點或者增加節點(修改DOM),加 key
只會移動減少操作DOM。
只有是同一個虛擬節點才會進行精細化比較,否則就是暴力刪除舊的,插入新的。
只進行同層比較,不會進行跨層比較。
diff算法的優化策略:四種命中查找,四個指針
舊前與新前(先比開頭,后插入和刪除節點的這種情況)
舊后與新后(比結尾,前插入或刪除的情況)
舊前與新后(頭與尾比,此種發生了,涉及移動節點,那么新前指向的節點,移動到舊后之后)
舊后與新前(尾與頭比,此種發生了,涉及移動節點,那么新前指向的節點,移動到舊前之前)
--- 問完上面這些如果都能很清楚的話,基本O了 ---
以下的這些簡單的概念,你肯定也是沒有問題的啦?
輕量級框架:只關注視圖層,是一個構建數據的視圖集合,大小只有幾十 kb
;
簡單易學:國人開發,中文文檔,不存在語言障礙 ,易于理解和學習;
雙向數據綁定:保留了 angular
的特點,在數據操作方面更為簡單;
組件化:保留了 react
的優點,實現了 html
的封裝和重用,在構建單頁面應用方面有著獨特的優勢;
視圖,數據,結構分離:使數據的更改更為簡單,不需要進行邏輯代碼的修改,只需要操作數據就能完成相關操作;
虛擬DOM:dom
操作是非常耗費性能的,不再使用原生的 dom
操作節點,極大解放 dom
操作,但具體操作的還是 dom
不過是換了另一種方式;
運行速度更快:相比較于 react
而言,同樣是操作虛擬 dom
,就性能而言, vue
存在很大的優勢。
路由鉤子的執行流程, 鉤子函數種類有:全局守衛、路由守衛、組件守衛
完整的導航解析流程:
導航被觸發。
在失活的組件里調用 beforeRouteLeave 守衛。
調用全局的 beforeEach 守衛。
在重用的組件里調用 beforeRouteUpdate 守衛 (2.2+)。
在路由配置里調用 beforeEnter。
解析異步路由組件。
在被激活的組件里調用 beforeRouteEnter。
調用全局的 beforeResolve 守衛 (2.5+)。
導航被確認。
調用全局的 afterEach 鉤子。
觸發 DOM 更新。
調用 beforeRouteEnter 守衛中傳給 next 的回調函數,創建好的組件實例會作為回調函數的參數傳入。
簡而言之,就是先轉化成AST樹,再得到的render函數返回VNode(Vue的虛擬DOM節點),詳細步驟如下:
首先,通過compile編譯器把template編譯成AST語法樹(abstract syntax tree 即 源代碼的抽象語法結構的樹狀表現形式),compile是createCompiler的返回值,createCompiler是用以創建編譯器的。另外compile還負責合并option。
然后,AST會經過generate(將AST語法樹轉化成render funtion字符串的過程)得到render函數,render的返回值是VNode,VNode是Vue的虛擬DOM節點,里面有(標簽名、子節點、文本等等)
Vue 實現響應式并不是在數據發生后立即更新 DOM,使用 vm.$nextTick
是在下次 DOM 更新循環結束之后立即執行延遲回調。在修改數據之后使用,則可以在回調中獲取更新后的 DOM。
什么時候被調用?
beforeCreate :實例初始化之后,數據觀測之前調用
created:實例創建萬之后調用。實例完成:數據觀測、屬性和方法的運算、 watch/event
事件回調。無 $el
.
beforeMount:在掛載之前調用,相關 render
函數首次被調用
mounted:了被新創建的vm.$el
替換,并掛載到實例上去之后調用改鉤子。
beforeUpdate:數據更新前調用,發生在虛擬DOM重新渲染和打補丁,在這之后會調用改鉤子。
updated:由于數據更改導致的虛擬DOM重新渲染和打補丁,在這之后會調用改鉤子。
beforeDestroy:實例銷毀前調用,實例仍然可用。
destroyed:實例銷毀之后調用,調用后,Vue實例指示的所有東西都會解綁,所有事件監聽器和所有子實例都會被移除
每個生命周期內部可以做什么?
created:實例已經創建完成,因為他是最早觸發的,所以可以進行一些數據、資源的請求。
mounted:實例已經掛載完成,可以進行一些DOM操作。
beforeUpdate:可以在這個鉤子中進一步的更改狀態,不會觸發重渲染。
updated:可以執行依賴于DOM的操作,但是要避免更改狀態,可能會導致更新無線循環。
destroyed:可以執行一些優化操作,清空計時器,解除綁定事件。
ajax放在哪個生命周期?:一般放在 mounted
中,保證邏輯統一性,因為生命周期是同步執行的, ajax
是異步執行的。單數服務端渲染 ssr
同一放在 created
中,因為服務端渲染不支持 mounted
方法。 什么時候使用beforeDestroy?:當前頁面使用 $on
,需要解綁事件。清楚定時器。解除事件綁定, scroll mousemove
。
受現代 JavaScript 的限制 ,Vue 無法檢測到對象屬性的添加或刪除。由于 Vue 會在初始化實例時對屬性執行 getter/setter 轉化,所以屬性必須在 data 對象上存在才能讓 Vue 將它轉換為響應式的。但是 Vue 提供了 Vue.set (object, propertyName, value) / vm.$set (object, propertyName, value)
來實現為對象添加響應式屬性,那框架本身是如何實現的呢?
我們查看對應的 Vue 源碼:vue/src/core/instance/index.js
export function set (target: Array<any> | Object, key: any, val: any): any { // target 為數組 if (Array.isArray(target) && isValidArrayIndex(key)) { // 修改數組的長度, 避免索引>數組長度導致splcie()執行有誤 target.length = Math.max(target.length, key) // 利用數組的splice變異方法觸發響應式 target.splice(key, 1, val) return val } // key 已經存在,直接修改屬性值 if (key in target && !(key in Object.prototype)) { target[key] = val return val } const ob = (target: any).__ob__ // target 本身就不是響應式數據, 直接賦值 if (!ob) { target[key] = val return val } // 對屬性進行響應式處理 defineReactive(ob.value, key, val) ob.dep.notify() return val }
我們閱讀以上源碼可知,vm.$set 的實現原理是:
如果目標是數組,直接使用數組的 splice 方法觸發相應式;
如果目標是對象,會先判讀屬性是否存在、對象是否是響應式,最終如果要對屬性進行響應式處理,則是通過調用 defineReactive 方法進行響應式處理( defineReactive 方法就是 Vue 在初始化對象時,給對象屬性采用 Object.defineProperty 動態添加 getter 和 setter 的功能所調用的方法)
讀到這里,這篇“vue高頻面試題實例分析”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注創新互聯行業資訊頻道。
當前題目:vue高頻面試題實例分析
新聞來源:http://m.newbst.com/article42/isgeec.html
成都網站建設公司_創新互聯,為您提供軟件開發、品牌網站建設、定制網站、、網站維護、外貿建站
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯