畢業之後就在一直合肥小公司工作,沒有老司機、沒有技術氛圍,在技術的道路上我只能獨自摸索。老闆也只會畫餅充飢,前途一片迷茫看不到任何希望。於是乎,我果斷辭職,在新年開工之際來到杭州,這裡的網際網路公司應該是合肥的幾十倍吧。。。。
剛來3天,面試了幾家公司,有些規模比較小,有些是創業公司,也有些已經發展的不錯了;今天把最近的面試題目做個彙總,也給自己復個盤,由於我的技術棧主要為Vue,所以大部分題目都是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. Vue 有哪些指令?
v-html、v-show、v-if、v-for等等
3. v-if 和 v-show 有什麼區別?
v-show 僅僅控制元素的顯示方式,將 display 屬性在 block 和 none 來回切換;而v-if會控制這個 DOM 節點的存在與否。當我們需要經常切換某個元素的顯示/隱藏時,使用v-show會更加節省效能上的開銷;當只需要一次顯示或隱藏時,使用v-if更加合理。
4. 簡述Vue的響應式原理
當一個Vue例項建立時,vue會遍歷data選項的屬性,用 Object.defineProperty 將它們轉為 getter/setter並且在內部追蹤相關依賴,在屬性被訪問和修改時通知變化。
每個元件例項都有相應的 watcher 程式例項,它會在元件渲染的過程中把屬性記錄為依賴,之後當依賴項的 setter 被呼叫時,會通知 watcher 重新計算,從而致使它關聯的元件得以更新。
5. Vue中如何在元件內部實現一個雙向資料繫結?
假設有一個輸入框元件,使用者輸入時,同步父元件頁面中的資料
具體思路:父元件通過 props 傳值給子元件,子元件通過 $emit 來通知父元件修改相應的props值,具體實現如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import Vue from 'vue' const component = { props: ['value'], template: ` <div> <input type="text" @input="handleInput" :value="value"> </div> `, data () { return { } }, methods: { handleInput (e) { this.$emit('input', e.target.value) } } } new Vue({ components: { CompOne: component }, el: '#root', template: ` <div> <comp-one :value1="value" @input="value = arguments[0]"></comp-one> </div> `, data () { return { value: '123' } } }) |
可以看到,當輸入資料時,父子元件中的資料是同步改變的:
我們在父元件中做了兩件事,一是給子元件傳入props,二是監聽input事件並同步自己的value屬性。那麼這兩步操作能否再精簡一下呢?答案是可以的,你只需要修改父元件:
1 2 3 4 5 6 |
template: ` <div> <!--<comp-one :value1="value" @input="value = arguments[0]"></comp-one>--> <comp-one v-model="value"></comp-one> </div> ` |
v-model 實際上會幫我們完成上面的兩步操作。
6. Vue中如何監控某個屬性值的變化?
比如現在需要監控data中,obj.a 的變化。Vue中監控物件屬性的變化你可以這樣:
1 2 3 4 5 6 7 8 |
watch: { obj: { handler (newValue, oldValue) { console.log('obj changed') }, deep: true } } |
deep屬性表示深層遍歷,但是這麼寫會監控obj的所有屬性變化,並不是我們想要的效果,所以做點修改:
1 2 3 4 5 6 7 |
watch: { 'obj.a': { handler (newName, oldName) { console.log('obj.a changed') } } } |
還有一種方法,可以通過computed 來實現,只需要:
1 2 3 4 5 |
computed: { a1 () { return this.obj.a } } |
利用計算屬性的特性來實現,當依賴改變時,便會重新計算一個新值。
7. Vue中給data中的物件屬性新增一個新的屬性時會發生什麼,如何解決?
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<template> <div> <ul> <li v-for="value in obj" :key="value"> {{value}} </li> </ul> <button @click="addObjB">新增obj.b</button> </div> </template> <script> export default { data () { return { obj: { a: 'obj.a' } } }, methods: { addObjB () { this.obj.b = 'obj.b' console.log(this.obj) } } } </script> <style></style> |
點選button會發現,obj.b 已經成功新增,但是檢視並未重新整理:
原因在於在Vue例項建立時,obj.b並未宣告,因此就沒有被Vue轉換為響應式的屬性,自然就不會觸發檢視的更新,這時就需要使用Vue的全域性api $set():
1 2 3 4 5 |
addObjB () { // this.obj.b = 'obj.b' this.$set(this.obj, 'b', 'obj.b') console.log(this.obj) } |
$set()方法相當於手動的去把obj.b處理成一個響應式的屬性,此時檢視也會跟著改變了:
8. delete和Vue.delete刪除陣列的區別
delete只是被刪除的元素變成了 empty/undefined 其他的元素的鍵值還是不變。
Vue.delete直接刪除了陣列 改變了陣列的鍵值。
1 2 3 4 5 6 |
var a=[1,2,3,4] var b=[1,2,3,4] delete a[1] console.log(a) this.$delete(b,1) console.log(b) |
9.如何優化SPA應用的首屏載入速度慢的問題?
- 將公用的JS庫通過script標籤外部引入,減小app.bundel的大小,讓瀏覽器並行下載資原始檔,提高下載速度;
- 在配置 路由時,頁面和元件使用懶載入的方式引入,進一步縮小 app.bundel 的體積,在呼叫某個元件時再載入對應的js檔案;
- 加一個首屏 loading 圖,提升使用者體驗;
10. 前端如何優化網站效能?
- 減少 HTTP 請求數量
在瀏覽器與伺服器進行通訊時,主要是通過 HTTP 進行通訊。瀏覽器與伺服器需要經過三次握手,每次握手需要花費大量時間。而且不同瀏覽器對資原始檔併發請求數量有限(不同瀏覽器允許併發數),一旦 HTTP 請求數量達到一定數量,資源請求就存在等待狀態,這是很致命的,因此減少 HTTP 的請求數量可以很大程度上對網站效能進行優化。
-
- CSS Sprites:國內俗稱 CSS 精靈,這是將多張圖片合併成一張圖片達到減少 HTTP 請求的一種解決方案,可以通過 CSS background 屬性來訪問圖片內容。這種方案同時還可以減少圖片總位元組數。
- 合併 CSS 和 JS 檔案:現在前端有很多工程化打包工具,如:grunt、gulp、webpack等。為了減少 HTTP 請求數量,可以通過這些工具再發布前將多個 CSS 或者 多個 JS 合併成一個檔案。
- 採用 lazyLoad:俗稱懶載入,可以控制網頁上的內容在一開始無需載入,不需要發請求,等到使用者操作真正需要的時候立即載入出內容。這樣就控制了網頁資源一次性請求數量。
- 控制資原始檔載入優先順序
瀏覽器在載入 HTML 內容時,是將 HTML 內容從上至下依次解析,解析到 link 或者 script 標籤就會載入 href 或者 src 對應連結內容,為了第一時間展示頁面給使用者,就需要將 CSS 提前載入,不要受 JS 載入影響。
一般情況下都是 CSS 在頭部,JS 在底部。
- 利用瀏覽器快取
瀏覽器快取是將網路資源儲存在本地,等待下次請求該資源時,如果資源已經存在就不需要到伺服器重新請求該資源,直接在本地讀取該資源。 - 減少重排(Reflow)
基本原理:重排是 DOM 的變化影響到了元素的幾何屬性(寬和高),瀏覽器會重新計算元素的幾何屬性,會使渲染樹中受到影響的部分失效,瀏覽器會驗證 DOM 樹上的所有其它結點的 visibility 屬性,這也是 Reflow 低效的原因。如果 Reflow 的過於頻繁,CPU 使用率就會急劇上升。
減少 Reflow,如果需要在 DOM 操作時新增樣式,儘量使用 增加 class 屬性,而不是通過 style 操作樣式。
- 減少 DOM 操作
- 圖示使用 IconFont 替換
11. 網頁從輸入網址到渲染完成經歷了哪些過程?
大致可以分為如下7步:
- 輸入網址;
- 傳送到DNS伺服器,並獲取域名對應的web伺服器對應的ip地址;
- 與web伺服器建立TCP連線;
- 瀏覽器向web伺服器傳送http請求;
- web伺服器響應請求,並返回指定url的資料(或錯誤資訊,或重定向的新的url地址);
- 瀏覽器下載web伺服器返回的資料及解析html原始檔;
- 生成DOM樹,解析css和js,渲染頁面,直至顯示完成;
12. jQuery獲取的dom物件和原生的dom物件有何區別?
js原生獲取的dom是一個物件,jQuery物件就是一個陣列物件,其實就是選擇出來的元素的陣列集合,所以說他們兩者是不同的物件型別不等價。
- 原生DOM物件轉jQuery物件:
1 2 |
var box = document.getElementById('box'); var $box = $(box); |
- jQuery物件轉原生DOM物件:
1 2 |
var $box = $('#box'); var box = $box[0]; |
13. jQuery如何擴充套件自定義方法
1 2 3 4 5 6 7 8 9 10 11 |
(jQuery.fn.myMethod=function () { alert('myMethod'); }) // 或者: (function ($) { $.fn.extend({ myMethod : function () { alert('myMethod'); } }) })(jQuery) |
使用:
1 |
$("#div").myMethod(); |
目前來看公司面試的問題還是比較基礎的,但是對於某些只追求會用並不研究其原理的同學來說可能就沒那麼容易了。所以大家不僅要追求學習的廣度,更要追求深度。
OK,希望自己能早日拿到心儀的offer.
參考:
淺談網站效能之前端效能優化