前端面試題總結
JavaScript面試題總結
CSS面試題總結
VUE面試題總結
說說你對 SPA 單頁面的理解,它的優缺點分別是什么?
SPA( single-page application )僅在 Web 頁面初始化時加載相應的 HTML、JavaScript 和 CSS。一旦頁面加載完成,SPA 不會因為用戶的操作而進行頁面的重新加載或跳轉;取而代之的是利用路由機制實現 HTML 內容的變換,UI 與用戶的交互,避免頁面的重新加載。
優點:
- 用戶體驗好、快,內容的改變不需要重新加載整個頁面,避免了不必要的跳轉和重復渲染;
- 基于上面一點,SPA 相對對服務器壓力小;
- 前后端職責分離,架構清晰,前端進行交互邏輯,后端負責數據處理;
缺點: - 初次加載耗時多:為實現單頁 Web 應用功能及顯示效果,需要在加載頁面的時候將 JavaScript、CSS 統一加載,部分頁面按需加載;
- 前進后退路由管理:由于單頁應用在一個頁面中顯示所有的內容,所以不能使用瀏覽器的前進后退功能,所有的頁面切換需要自己建立堆棧管理;
- SEO 難度較大:由于所有的內容都在一個頁面中動態替換顯示,所以在 SEO 上其有著天然的弱勢。
computed 和 watch 的區別和運用的場景
computed: 是計算屬性,依賴其它屬性值,并且 computed 的值有緩存,只有它依賴的屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值;
watch:更多的是「觀察」的作用,類似于某些數據的監聽回調 ,每當監聽的數據變化時都會執行回調進行后續操作;
運用場景:
當我們需要進行數值計算,并且依賴于其它數據時,應該使用 computed,因為可以利用 computed 的緩存特性,避免每次獲取值時,都要重新計算;
當我們需要在數據變化時執行異步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行異步操作 ( 訪問一個 API ),限制我們執行該操作的頻率,并在我們得到最終結果前,設置中間狀態。這些都是計算屬性無法做到的。
談談對生命周期的理解
- beforeCreate階段:vue實例的掛載元素el和數據對象data都是undefined,還沒有初始化。
created階段:vue實例的數據對象data有了,可以訪問里面的數據和方法,未掛載到DOM,el還沒有 - beforeMount階段:vue實例的el和data都初始化了,但是掛載之前為虛擬的dom節點
- mounted階段:vue實例掛載到真實DOM上,就可以通過DOM獲取DOM節點
- beforeUpdate階段:響應式數據更新時調用,發生在虛擬DOM打補丁之前,適合在更新之前訪問現有的DOM,比如手動移除已添加的事件監聽器
- updated階段:虛擬DOM重新渲染和打補丁之后調用,組成新的DOM已經更新,避免在這個鉤子函數中操作數據,防止死循環
- beforeDestroy階段:實例銷毀前調用,實例還可以用,this能獲取到實例,常用于銷毀定時器,解綁事件
-
destroyed階段:實例銷毀后調用,調用后所有事件監聽器會被移除,所有的子實例都會被銷毀
生命周期圖示
在哪個生命周期內調用異步請求?
可以在鉤子函數 created、beforeMount、mounted 中進行調用,因為在這三個鉤子函數中,data 已經創建,可以將服務端端返回的數據進行賦值。
推薦在 created 鉤子函數中調用異步請求,因為在 created 鉤子函數中調用異步請求有以下優點:
- 能更快獲取到服務端數據,減少頁面 loading 時間;
- ssr 不支持 beforeMount 、mounted 鉤子函數,所以放在 created 中有助于一致性;
在什么階段才能訪問操作DOM?
在鉤子函數 mounted 被調用前,Vue 已經將編譯好的模板掛載到頁面上,所以在 mounted 中可以訪問操作 DOM
父組件可以監聽到子組件的生命周期嗎?
可以通過@hook來監聽生命周期事件,用法如下:
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
doSomething() {
console.log('父組件監聽到 mounted 鉤子函數 ...');
},
// Child.vue
mounted(){
console.log('子組件觸發 mounted 鉤子函數 ...');
},
// 以上輸出順序為:
// 子組件觸發 mounted 鉤子函數 ...
// 父組件監聽到 mounted 鉤子函數 ...
談談你對 keep-alive 的了解? (詳解)
keep-alive 是 Vue 內置的一個組件,可以使被包含的組件保留狀態,避免重新渲染 ,其有以下特性:
一般結合路由和動態組件一起使用,用于緩存組件
提供 include 和 exclude 屬性,兩者都支持字符串或正則表達式, include 表示只有名稱匹配的組件會被緩存,exclude 表示任何名稱匹配的組件都不會被緩存 ,其中 exclude 的優先級比 include 高;
對應兩個鉤子函數 activated 和 deactivated ,當組件被激活時,觸發鉤子函數 activated,當組件被移除時,觸發鉤子函數 deactivated。
組件中 data 為什么是一個函數?
因為組件是用來復用的,且 JS 里對象是引用關系,如果組件中 data 是一個對象,那么這樣作用域沒有隔離,子組件中的 data 屬性值會相互影響,如果組件中 data 選項是一個函數,那么每個實例可以維護一份被返回對象的獨立的拷貝,組件實例之間的 data 屬性值不會互相影響;而 new Vue 的實例,是不會被復用的,因此不存在引用對象的問題。
vue-router 路由模式有幾種?
vue-router 有 3 種路由模式:hash、history、abstract,對應的源碼如下所示:
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
hash: 使用 URL hash 值來作路由。支持所有瀏覽器,包括不支持 HTML5 History Api 的瀏覽器;
history : 依賴 HTML5 History API 和服務器配置。具體可以查看 HTML5 History 模式;
abstract : 支持所有 JavaScript 運行環境,如 Node.js 服務器端。如果發現沒有瀏覽器的 API,路由會自動強制進入這個模式.
vuex有哪幾種狀態和屬性 (詳解)
- state中保存著共有數據,數據是響應式的
- getter可以對state進行計算操作,主要用來過濾一些數據,可以在多組件之間復用
- mutations定義的方法動態修改state中的數據,通過commit提交方法,方法必須是同步的
- actions將mutations里面處理數據的方法變成異步的,就是異步操作數據,通store.dispatch來分發actions,把異步的方法寫在actions中,通過commit提交mutations,進行修改數據。
- modules:模塊化vuex
vue修飾符
- stop:阻止事件的冒泡
- prevent:阻止事件的默認行為
- once:只觸發一次
- self:只觸發自己的事件行為時,才會執行
Vue實現數據雙向綁定的原理:Object.defineProperty()
vue實現數據雙向綁定主要是:采用數據劫持結合發布者-訂閱者模式的方式,通過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變動時發布消息給訂閱者,觸發相應監聽回調。當把一個普通 Javascript 對象傳給 Vue 實例來作為它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉為 getter/setter。用戶看不到 getter/setter,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。
vue的數據雙向綁定 將MVVM作為數據綁定的入口,整合Observer,Compile和Watcher三者,通過Observer來監聽自己的model的數據變化,通過Compile來解析編譯模板指令(vue中是用來解析 {{}}),最終利用watcher搭起observer和Compile之間的通信橋梁,達到數據變化 —>視圖更新;視圖交互變化(input)—>數據model變更雙向綁定效果。
說說對v-model的了解?
v-model本質就是一個語法糖,可以看成是value + input方法的語法糖。 可以通過model屬性的prop和event屬性來進行自定義。原生的v-model,會根據標簽的不同生成不同的事件和屬性。
我們在 vue 項目中主要使用 v-model 指令在表單 input、textarea、select 等元素上創建雙向數據綁定,我們知道 v-model 本質上不過是語法糖,v-model 在內部為不同的輸入元素使用不同的屬性并拋出不同的事件:
text 和 textarea 元素使用 value 屬性和 input 事件;
checkbox 和 radio 使用 checked 屬性和 change 事件;
select 字段將 value 作為 prop 并將 change 作為事件。
以 input 表單元素為例:
<input v-model='something'>
相當于
<input v-bind:value="something" v-on:input="something = $event.target.value">
如果在自定義組件中,v-model 默認會利用名為 value 的 prop 和名為 input 的事件,如下所示:
父組件:
<Child v-model="message"></Child>
子組件
<div>{{value}}</div>
props:{
value: String
},
methods: {
test1(){
this.$emit('input', '小紅')
},
}
Vue 項目優化
1.代碼層面的優化
v-if 和 v-show 區分使用場景
computed 和 watch 區分使用場景
v-for 遍歷必須為 item 添加 key,且避免同時使用 v-if
長列表性能優化
事件的銷毀
圖片資源懶加載
路由懶加載
第三方插件的按需引入
優化無限列表性能
服務端渲染 SSR or 預渲染
2.Webpack 層面的優化
Webpack 對圖片進行壓縮
減少 ES6 轉為 ES5 的冗余代碼
提取公共代碼
模板預編譯
提取組件的 CSS
優化 SourceMap
構建結果輸出分析
Vue 項目的編譯優化
3.基礎的 Web 技術的優化
開啟 gzip 壓縮
瀏覽器緩存
CDN 的使用
使用 Chrome Performance 查找性能瓶頸