2020VUE面試題常考-基礎點


一:對 SPA 單⻚⾯的理解,優缺點是什么?

 SPA( single-page application )僅在 Web ⻚⾯初始化時加載相應的 HTML、JavaScript 和 CSS。⼀旦⻚⾯加載完成,SPA 不會因為⽤戶的操作⽽進⾏⻚⾯的重新加載或跳轉;取⽽代之的是利⽤路由機制實現 HTML 內容的變換,UI 與⽤戶的交互,避免⻚⾯的重新加載。

優點:

1)⽤戶體驗好、快,內容的改變不需要重新加載整個⻚⾯,避免了不必要的跳轉和重復渲染;

2)SPA 相對對服務器壓⼒⼩;

3)前后端職責分離,架構清晰,前端進⾏交互邏輯,后端負責數據處理;

缺點:

1)⾸屏(初次)加載慢:為實現單⻚ Web 應⽤功能及顯示效果,需要在加載⻚⾯的時候將JavaScript、CSS 統⼀加載,部分⻚⾯按需加載;

2)不利於 SEO:由於所有的內容都在⼀個⻚⾯中動態替換顯示,所以在 SEO 上其有着天然的弱勢。

二:new Vue() 發生了什么?

1)結論:new Vue()是創建Vue實例,它內部執行了根實例的初始化過程。

2)具體包括以下操作:

  • 選項合並

  • $children,$refs,$slots,$createElement等實例屬性的方法初始化

  • 自定義事件處理

  • 數據響應式處理

  • 生命周期鈎子調用 (beforecreate created)

  • 可能的掛載

3)總結:new Vue()創建了根實例並准備好數據和方法,未來執行掛載時,此過程還會遞歸的應用於它的子組件上,最終形成一個有緊密關系的組件實例樹

源碼地址:src/core/instance/init.js

三:Vue.use是干什么的?原理是什么?

核心答案:

vue.use 是用來使用插件的,我們可以在插件中擴展全局組件、指令、原型方法等。

1、檢查插件是否注冊,若已注冊,則直接跳出;

2、處理入參,將第一個參數之后的參數歸集,並在首部塞入 this 上下文;

3、執行注冊方法,調用定義好的 install 方法,傳入處理的參數,若沒有 install 方法並且插件本身為 function 則直接進行注冊;

 

1) 插件不能重復的加載

install 方法的第一個參數是vue的構造函數,其他參數是Vue.set中除了第一個參數的其他參數; 代碼:args.unshift(this)

2) 調用插件的install 方法 代碼:typeof plugin.install === 'function'

3) 插件本身是一個函數,直接讓函數執行。 代碼:plugin.apply(null, args)

4) 緩存插件。  代碼:installedPlugins.push(plugin)

源碼地址:src/core/global-api/use.js

四:請說一下響應式數據的理解?

根據數據類型來做不同處理,數組和對象類型當值變化時如何劫持。

1) 對象內部通過defineReactive方法,使用 Object.defineProperty() 監聽數據屬性的 get 來進行數據依賴收集,再通過 set 來完成數據更新的派發;

2) 數組則通過重寫數組方法來實現的。擴展它的 7 個變更⽅法,通過監聽這些方法可以做到依賴收集和派發更新;( push/pop/shift/unshift/splice/reverse/sort )

這里在回答時可以帶出一些相關知識點 (比如多層對象是通過遞歸來實現劫持,順帶提出vue3中是使用 proxy來實現響應式數據)

補充回答:

內部依賴收集是怎么做到的,每個屬性都擁有自己的dep屬性,存放他所依賴的 watcher,當屬性變化后會通知自己對應的 watcher去更新。

響應式流程:

1、defineReactive  把數據定義成響應式的;

2、給屬性增加一個 dep,用來收集對應的那些watcher;

3、等數據變化進行更新

dep.depend()  // get 取值:進行依賴收集

dep.notify() // set 設置時:通知視圖更新

這里可以引出性能優化相關的內容:1)對象層級過深,性能就會差。2)不需要響應數據的內容不要放在data中。3)object.freeze()  可以凍結數據。

源碼地址:src/core/observer/index.js 158

五:Vue如何檢測數組變化?

數組考慮性能原因沒有用defineProperty對數組的每一項進行攔截,而是選擇重寫數組 方法以進行重寫。當數組調用到這 7 個方法的時候,執行 ob.dep.notify() 進行派發通知 Watcher 更新;

* 重寫數組方法:push/pop/shift/unshift/splice/reverse/sort

補充回答:

在Vue中修改數組的索引和長度是無法監控到的。需要通過以下7種變異方法修改數組才會觸發數組對應的wacther進行更新。數組中如果是對象數據類型也會進行遞歸劫持。

說明:那如果想要改索引更新數據怎么辦?

可以通過Vue.set()來進行處理 =》 核心內部用的是 splice 方法。

// 取出原型方法;
const arrayProto = Array.prototype  
// 拷貝原型方法;
export const arrayMethods = Object.create(arrayProto)  
// 重寫數組方法;
def(arrayMethods, method, function mutator (...args) { }
ob.dep.notify()  // 調用方法時更新視圖;

源碼地址:src/core/observer/array.js 15

六:Vue.set 方法是如何實現的?

核心答案:

為什么$set可以觸發更新,我們給對象和數組本身都增加了dep屬性,當給對象新增不存在的屬性則觸發對象依賴的watcher去更新,當修改數組索引時我們調用數組本身的splice方法去更新數組。

補充回答:

官方定義 Vue.set(object, key, value) 

1) 如果是數組,調用重寫的splice方法 (這樣可以更新視圖 )

代碼:target.splice(key, 1, val)

2) 如果不是響應式的也不需要將其定義成響應式屬性。

3) 如果是對象,將屬性定義成響應式的  defineReactive(ob.value, key, val)

通知視圖更新  ob.dep.notify()

源碼地址:src/core/observer/index.js 202

七:Vue中模板編譯原理?

核心答案:

如何將template轉換成render函數(這里要注意的是我們在開發時盡量不要使用template,因為將template轉化成render方法需要在運行時進行編譯操作會有性能損耗,同時引用帶有complier包的vue體積也會變大) 默認.vue文件中的 template處理是通過vue-loader 來進行處理的並不是通過運行時的編譯。

1) 將 template 模板轉換成 ast 語法樹 - parserHTML

2) 對靜態語法做靜態標記 - markUp

3) 重新生成代碼 - codeGen

補充回答:

模板引擎的實現原理就是new Function + with來進行實現的。

vue-loader中處理template屬性主要靠的是 vue-template-compiler

vue-loader

// template => ast => codegen => with+function 實現生成render方法 
let {ast, render } = VueTemplateCompiler.compile(`<div>{{aaa}}</div>`)
console.log(ast, render)

// 模板引擎的實現原理 with + new Function
console.log(new Function(render).tostring())
// render方法執行完畢后生成的是虛擬 dom
// with(this){return _c('div',[_s(aaa)])}
// 代碼生成

源碼設置:

const ast = parse(template.trim(), options) // 將代碼解析成ast語法樹
  if (options.optimize !== false) {
    optimize(ast, options) // 優化代碼 標記靜態點 標記樹
  }
  const code = generate(ast, options) // 生成代碼 

源碼地址:src/compiler/index.js

八:Proxy 與 Object.defineProperty 優劣對比

核心答案:

Proxy 的優勢如下:

1)Proxy 可以直接監聽對象而非屬性;

2)Proxy 可以直接監聽數組的變化;

3)Proxy 有多達 13 種攔截方法,不限於 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具備的;4)Proxy 返回的是一個新對象,我們可以只操作新的對象達到目的,而 Object.defineProperty 只能遍歷對象屬性直接修改;

5)Proxy 作為新標准將受到瀏覽器廠商重點持續的性能優化,也就是傳說中的新標准的性能紅利;

Object.defineProperty 的優勢如下:

兼容性好,支持 IE9,而 Proxy 的存在瀏覽器兼容性問題,而且無法用 polyfill 磨平,因此 Vue 的作者才聲明需要等到下個大版本( 3.0 )才能用 Proxy 重寫。

九:Vue3.x響應式數據原理

Vue3.x改用Proxy替代Object.defineProperty。因為Proxy可以直接監聽對象和數組的變化,並且有多達13種攔截方法。並且作為新標准將受到瀏覽器廠商重點持續的性能優化。

Proxy只會代理對象的第一層,那么Vue3又是怎樣處理這個問題的呢?

判斷當前Reflect.get的返回值是否為Object,如果是則再通過reactive方法做代理, 這樣就實現了深度觀測。

監測數組的時候可能觸發多次get/set,那么如何防止觸發多次呢?

我們可以判斷key是否為當前被代理對象target自身屬性,也可以判斷舊值與新值是否相等,只有滿足以上兩個條件之一時,才有可能執行trigger。

 

 

來自VUE中文社區公眾號 https://mp.weixin.qq.com/s/60HI-CM1GhqDG5zeTFSOrw

 


免責聲明!

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



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