臨近2019年的尾聲,是否是該爲了更好的2020年再戰一回呢? ‘勝敗兵家事不期,包羞忍恥是男兒。江東子弟多才俊,捲土重來未可知’,那些在秋招失利的人,難道就心甘情願放棄嗎!css
此文總結2019年以來本人經歷以及瀏覽文章中,較熱門的一些面試題,涵蓋從CSS到JS再到Vue再到網絡等前端基礎到進階的一些知識。html
總結面試題涉及的知識點是對本身的一個提高,也但願能夠幫助到同窗們,在2020年會有一個更好的競爭能力。前端
css篇
- juejin.im/post/5e040e…Javavscript篇
- juejin.im/post/5e2122…ECMAScript 6篇
- juejin.im/post/5e2962…MVC
指的是Model-View-Controller
,即模型-視圖-控制器。
MVC
的目的就是將模型與視圖分離MVC
屬於單向通訊,必須經過Controller
來承上啓下,既必須由控制器來獲取數據,將結果返回給前端,頁面從新渲染MVVM
指的是Model-View-ViewModel
,即模型-視圖-視圖模型,「模型」指的是後端傳遞的數據,「視圖」指的是所看到的頁面,「視圖模型」是MVVM
的核心,它是鏈接View
與Model
的橋樑,實現view
的變化會自動更新到viewModel
中,viewModel
中的變化也會自動顯示在view
上,是一種數據驅動視圖的模型區別:vue
MVC
中的Control
在MVVM
中演變成viewModel
MVVM
經過數據來顯示視圖,而不是經過節點操做MVVM
主要解決了MVC
中大量的DOM
操做,使頁面渲染性能下降,加載速度慢,影響用戶體驗的問題Vue
底層對於響應式數據的核心是object.defineProperty
,Vue
在初始化數據時,會給data
中的屬性使用object.defineProperty
從新定義屬性(劫持屬性的getter
和setter
),當頁面使用對應屬性時,會進行依賴收集(收集當前組件的watcher
),若是屬性發生變化,會通知相關依賴進行更新操做node
Vue
經過數據劫持配合發佈者-訂閱者的設計模式,內部經過調用object.defineProperty()
來劫持各個屬性的getter
和setter
,在數據變化的時候通知訂閱者,並觸發相應的回調push,pop,unshift,shift···
)Vue
將data
中的數組,進行了原型鏈的重寫,指向了本身所定義的數組原型方法,當調用數組的API
時,能夠通知依賴更新,若是數組中包含着引用類型,會對數組中的引用類型再次進行監控由於若是不採用異步渲染,那麼每次更新數據都會進行從新渲染,爲了提升性能,Vue
經過異步渲染的方式,在本輪數據更新後,再去異步更新視圖面試
Object.defineProperty
只能劫持對象的屬性,所以須要遍歷對象的每一個屬性,而Proxy
能夠直接代理對象Object.defineProperty
對新增屬性須要手動進行觀察,因爲Object.defineProperty
劫持的是對象的屬性(第一點),因此新增屬性時,須要從新遍歷對象,對其新增屬性再使用Object.defineProperty
進行劫持 (正是這個緣由致使咱們在給data
中的數組或對象新增屬性時,須要使用$set
才能保證視圖能夠更新)Proxy
性能高,支持13種攔截方式EventLoop
事件循環dom
更新循環結束後執行延遲迴調,當咱們修改數據以後當即使用nextTick()
來獲取最新更新的Dom當用戶指定了watch
中的deep:true
時,若是當前監控的值是數組類型(對象類型),會對對象中的每一項進行求值,此時會將當前watcher
存入到對應屬性的依賴中,這樣數組中的對象發生變化也會通知數據進行更新vue-router
缺點:因爲須要對每一項都進行操做,性能會下降,不建議屢次使用deep:true
vuex
v-for
優先級高於v-if
,若是連在一塊兒使用的話會把v-if
給每個元素都添加上,重複運行於每個v-for
循環中,會形成性能浪費後端
在Vue
中,組件都是可複用的,一個組件建立好後,能夠在多個地方重複使用,而無論複用多少次,組件內的data
都必須是相互隔離,互不影響的,若是data
以對象的形式存在,因爲Javascript
中對象是引用類型,做用域沒有隔離,所以data
必須以函數的形式返回設計模式
❗ 小知識: new Vue
根組件不須要複用,所以不須要以函數方式返回
key
是爲每一個vnode
指定惟一的id
,在同級vnode
的Diff
過程當中,能夠根據key
快速的進行對比,來判斷是否爲相同節點,並利用key
的惟一性生成map
來更快的獲取相應的節點,另外指定key
後,能夠保證渲染的準確性
beforeCreate
→ 在實例初始化以後,數據觀測(data observer
)以前被調用created
→ 實例已經建立完成以後被調用。在這裏,實例已完成如下配置:
data observer
)watch/event
事件回調$el
beforeMount
→ 在掛載開始以前被調用,相關的render
函數首次被調用mounted
→ $el
被新建立的vm.$el
替換,並掛載到實例上以後調用該鉤子beforeUpdate
→ 數據更新時調用,發生在虛擬DOM
從新渲染和打補丁以前updated
→ 因爲數據更改致使的虛擬DOM
從新渲染和打補丁,在這以後會調用該鉤子(該鉤子在服務器端渲染期間不被調用)beforeDestroy
→ 實例銷燬以前調用,在這裏,實例仍然徹底可使用destroyed
→ Vue
實例銷燬後調用。調用該鉤子後,Vue
實例指示的全部東西都會解綁,全部的事件監聽器會被移除,全部的子實例也會被銷燬(該鉤子在服務器端渲染期間不被調用)created
→ 實例已經建立完成,因爲它是最先觸發的,因此能夠進行一些數據,資源的請求mounted
→ 實例已經掛載完成,能夠進行一些DOM
操做beforeUpdate
→ 能夠在該鉤子中進一步地更改狀態,這不會觸發附加的渲染過程updated
→ 能夠執行依賴於DOM
的操做。但在大多數狀況下,應避免在該鉤子中更改狀態,由於這可能致使更新無限循環destroyed
→ 能夠執行一些優化操做,例如清空定時器,清理緩存,解除事件綁定等「beforeCreate
」、「created
」、「beforeMount
」、「mounted
」、「beforeUpdate
」、「updated
」、「beforeDestroy
」、「destroyed
」
❗ 小知識:
<keep-alive>
擁有本身獨立的鉤子函數 activated
| deactivated
activated
→ 在被<keep-alive>
包裹的組件中才有效,當組件被激活時使用該鉤子deactivated
→ 在被<keep-alive>
包裹的組件中才有效,當組件被中止時使用該鉤子父組件掛載完成必須是等到子組件都掛載完成以後,纔算父組件掛載完,因此父組件的
mounted
確定是在子組件mounted
以後
So:「父」beforeCreate → 「父」created → 「父」beforeMount → 「子」beforeCreate → 「子」created → 「子」beforeMount → 「子」mounted → 「父」mounted
子組件更新過程(取決於對父組件是否有影響)
父組件更新過程(取決於對子組件是否有影響)
銷燬過程
vue
中,父組件能夠經過prop
將數據傳遞給子組件,但這個prop
只能由父組件來修改,子組件修改的話會拋出錯誤$emit
由子組件派發事件,並由父組件接收事件進行修改因爲vue
提倡單向數據流,即父級props
的更新會流向子組件,但反過來則不行。這是爲了防止意外的改變父組件的狀態,使得應用的數據流變得難以理解。若是破壞了單項數據流,當應用複雜時,debug的成本將會很是高
父子組件通訊
props
/ event
$parent
/ $children
ref
provide
/ inject
.sync
非父子組件通訊
eventBus
$root
vuex
$attr
/ $listeners
provide
/ inject
❗ 小知識: 關於.sync
的使用
假設有一個組件 comp
<comp :foo.sync="bar"></comp>
傳遞foo值並用sync修飾,會被擴展成
<comp :foo="bar" @update:foo="val => bar = val"></comp>
複製代碼
當子組件comp須要更新foo的值時,它須要顯示地觸發一個更新事件
this.$emit('update:foo', newValue)
複製代碼
多個組件經過同一個掛載點進行組件的切換,
is
的值是哪一個組件的名稱,那麼頁面就會顯示哪一個組件
<div :is='xxx'></div>
複製代碼
組件是能夠在它們本身的模板中調用自身的,不過它們只能經過
name
選項來作這件事
首先咱們要知道,既然是遞歸組件,那麼必定要有一個結束的條件,不然就會致使組件無限循環使用,最終出現
max stack size exceeded
的錯誤,也就是棧溢出。因此,咱們應該使用v-if = 'false'
來做爲遞歸組件的結束條件,當遇到v-if = 'false'
時,組件將不會再進行渲染
v-model
本質是v-bind
和v-on
的語法糖,用來在表單控件或組件上建立雙向綁定。
<input v-model='searchText'>
等價於
<input
v-bind:value='searchText'
v-on:input='searchText = $event.target.value'>
複製代碼
在一個組件上使用v-model
,默認會爲組件綁定名爲value
的prop
和名爲input
的事件
vuex
和全局對象主要有兩大區別:
vuex
的狀態存儲是響應式的。當vue
組件從store
中讀取狀態時,若store
中的狀態發生變化,那麼相應的組件也會獲得高效更新store
中的狀態,改變store
中的狀態惟一方法是顯示地提交mutation
(commit
)。這樣使得咱們能夠方便地跟蹤每個狀態的變化vuex
中全部的狀態更新的惟一方式都是提交mutation
,異步操做須要經過action
來提交mutation
(dispatch
)。這樣使得咱們能夠方便地跟蹤每個狀態的變化,從而讓咱們可以實現一些工具幫助咱們更好地使用vuex
每一個mutation
執行完後都會對應獲得一個新的狀態變動,這樣devtools
就能夠打個快照存下來,而後就能夠實現time-travel
了。
若是mutation
支持異步操做,就沒有辦法知道狀態是什麼時候更新,沒法很好的進行狀態追蹤,影響調試效率
v-if
指若是條件不成立則不會渲染當前指令所在節點的Dom
元素,會在切換過程當中對條件塊的事件監聽器和子組件進行銷燬和重建v-show
只是基於css
進行切換,無論條件是什麼,都會進行渲染(切換display:block | none
)So:v-if
切換的開銷較大,而v-show
初始化的開銷較大,因此在須要頻繁切換顯示和隱藏的Dom
元素時,使用v-show
更合適,渲染後不多進行切換則使用v-if
較合適
computed
是依賴於其餘屬性的一個計算值,而且具有緩存,只有當依賴的值發生變化纔會更新(自動監聽依賴值的變化,從而動態返回內容)watch
是在監聽的屬性發生變化的時候,觸發一個回調,在回調中執行一些邏輯So:computed
和watch
區別在於用法上的不一樣,computed
適合在模板渲染中,若是是須要經過依賴來獲取動態值,就可使用計算屬性。而若是是想在監聽值變化時執行業務邏輯,就使用watch
computed
是基於它們響應式依賴進行緩存,只有在依賴值發生變化,纔會進行計算求值methods
每次使用都會執行相應的方法v-html
能夠用來識別HTML標籤並渲染出去
致使問題: 在網站上動態渲染任意Html
,很容易致使受到Xss
攻擊,因此只能在可信內容上使用v-html
,且永遠不能用於用戶提交的內容上
包裹在<keep-alive>
裏組件,在切換時會保存其組件的狀態,使其不被銷燬,防止屢次渲染,
· keep-alive
擁有兩個獨立的生命週期(activated
| deactivated
),使keep-alive
包裹的組件在切換時不被銷燬,而是緩存到內存中並執行deactivated
鉤子,切換回組件時會獲取內存,渲染後執行activated
鉤子
var app = new Vue({
el: '#app',
data: {
},
// 建立指令(能夠多個)
directives: {
// 指令名稱
dir1: {
inserted(el) {
// toDo
}
}
}
})
複製代碼
Vue.directive('dir2', {
inserted(el) {
// inserted 表示元素插入時
// toDo
}
})
複製代碼
<div id="app">
<div :dir1='..'></div>
</div>
複製代碼
var app = new Vue({
el: '#app',
data: {
},
// 建立指令(能夠多個)
filters: {
// 指令名稱
newfilter:function(value){
// toDo
}
}
})
複製代碼
Vue.filter('newfilter', function (value) {
// toDo
})
複製代碼
<div>{{xxx | newfilter}}</div>
複製代碼
.prevent
:攔截默認事件.passive
:不攔截默認事件.stop
:阻止事件冒泡.self
:當事件發生在該元素而不是子元素的時候會觸發.capture
:事件偵聽,事件發生的時候會調用vue
的目的是經過儘量簡單的API
實現相應的數據綁定和組合的視圖組件,核心是一個響應的數據綁定系統。MVVM
,數據驅動,組件化,輕量,簡潔,高效,快速。在
<style>
標籤上寫入scoped
便可
route
表示路由信息對象,包括path
,params
,hash
,query
,fullPath
,matched
,name
等路由信息參數router
表示路由實例對象,包括了路由的跳轉方法,鉤子函數等beforeEach
,beforeResolve
,afterEach
beforeEnter
beforeRouteEnter
,beforeRouteUpdate
,beforeRouteLeave
導航解析流程:
beforeRouteLeave
離開守衛beforeEach
守衛beforeRouteUpdate
守衛beforeEnter
守衛beforeRouteEnter
守衛beforeResolve
守衛afterEach
守衛Dom
更新beforeRouteEnter
守衛中傳給next
的回調hash
模式會在url
上顯示'#',而history
模式沒有hash
模式能夠正常加載到hash
值對應的頁面,history
模式沒有處理的話,會返回404,通常須要後端將全部頁面都配置重定向到首頁路由hash
模式能夠支持低版本瀏覽器和IEhash
模式
#
後面hash
值的變化,不會致使瀏覽器向服務器發出請求,瀏覽器不發出請求,就不會刷新頁面,同時經過監聽hashchange
事件能夠知道hash
發生了哪些變化。根據hash
變化來實現頁面的局部更新history
模式
history
模式的實現,主要是Html5
標準發佈的兩個Api(pushState
和replaceState
),這兩個Api能夠改變url
,可是不會發送請求,這樣就能夠監聽url
的變化來實現局部更新path
屬性過程當中,使用動態路徑參數,以冒號開頭{
path:'/details/:id',
name:'Details',
components:Details
}
# 訪問`details`前綴下的路徑,例如`details/1`,`details/2`等,都會映射到`Details`這個組件
複製代碼
/details
下的路由時,參數值會被設置到this.$route.params
下,因此經過這個屬性能夠獲取動態參數this.$route.params.id
複製代碼
params
name
,不能用path
url
上query
path
,不能用name
name
可使用path
路徑url
上state
中)Ajax
請求次數,有些情景能夠直接從內存中的State
獲取vuex
中的State
就會從新變回初始化狀態State
:vuex
的基本數據,用來存儲變量Getter
:從基本數據state
派生的數據,至關於state
的計算屬性Mutation
:提交更新數據的方法,必須是同步的(須要異步則使用action
)。每一個mutation
都有一個字符串的事件類型(type
)和一個回調函數(handler
)Action
:和mutation
的功能大體相同,不一樣在於
action
提交的是mutation
,而不是直接變動狀態action
能夠包含任意異步操做Module
:模塊化vuex
,可讓每個模塊擁有本身的state
,mutation
,action
,getter
,使得結構清晰,方便管理vuex
就是一個倉庫,倉庫裏面放了不少對象,其中state
就是數據源存放地state
裏面存放的數據是響應式的,Vue
組件從store
中讀取數據,如果store
中的數據改變,依賴這個數據的組件也會更新數據mapState
把全局的state
和getters
映射到當前組件的computed
計算屬性中getters
能夠對state
進行計算操做,能夠把它看作store
的computed
計算屬性getters
能夠在多個組件之間複用getters
vuex
的state
裏action
裏,方便複用;若是不須要複用這個請求,直接寫在Vue
文件裏會更方便