面試題 大牛答面試
大牛答面試
#一、 說說React生命週期?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 4星 | react | react核心概念 | 元件化 |
#1. 通常解法
React的生命週期相比於vue要更加有深度,名稱叫起來也比較長,不是很容易記憶,尤其是react生命週期的使用,有很多細節可以體現出開發人員對react的理解程度。比如他的週期官方一般指:
建立期:
componentWillMount 元件DOM建立之前
componentDidMount 元件DOM建立完成
存在期:
componentWillReceiveProps 元件接收新props資料之前
shouldComponentUpdate 元件是否應該更新
componentWillUpdate 元件更新之前
componentDidUpdate 元件更新之後
銷燬期:
componentWillUnmount 元件即將銷燬
#2. 通用大牛級解法
在上面的基礎加上:
constructor 初始化階段
render 渲染階段
另外解釋具體的周期函式特點比如:
shouldComponentUpdate
這個函式可以接受三個引數分別是nextProps,nextState,nextContext,此函式可以省略不寫,但是如果寫就必須返回一個boolean,這點跟其他周期函式不同。我們可以利用這個函式對元件前後歷史的資料進行對比從而實現元件效能優化,就是說通過對比發現數據沒有真正更新就阻止周期函式繼續執行,如果過發現數據有更新則允許週期繼續執行。但需要提醒的是,該函式雖然可以用來做優化,如果不是確定能帶來優化效果,儘量不要人為設定,react自身的效能就已經很高,應該優先考慮利用react自身的能力。
社群提供了第三方工具比如:
react-addons-pure-render-mixin
immutable.js
可以讓我們結合shouldComponentUpdate對專案進一步進行優化,減少元件不必要的更新。另外react-addons-pure-render-mixin該工具是早期react優化的方案之一,但是現在新版的react已不再需要該工具,取而代之的是react提供的PureComponent元件,該元件跟普通元件相比沒有shouldComponentUpdate函式,而是自動對前後歷史資料進行淺對比,來阻止不必要的更新。但由於PureComponent進行的是淺對比,所以如果元件資料巢狀引用型別的話,會導致出現bug,這個時候就需要結合immutable來解決問題
#3. 解法對比及優缺點
通常解法,是對react特點的基本闡述,一般使用也已足夠。但是如果因為業務太複雜,邏輯較深,頻繁進行週期執行從而導致頁面效能下降,這個時候就該考慮結合shouldComponentUpdate函式進行優化,只是這樣會增加業務複雜度,而且使用不當反而會適得其反。所以也需要慎用。
#4. 延伸及擴充套件問題回答參考
問題: 在react中如何獲取DOM,ref的使用有什麼限制?
解答:
1、react是mvvm框架,優先考慮資料驅動檢視,如果真的需要操作dom,可以使用ref屬性,也可以使用findDOMNode函式。需要注意的是,操作DOM必須在componentDidMount之後才可以,因為這個週期之前DOM尚未生成,操作會報錯。
Ref屬性的值可以是字元也可以是函式,官方推薦函式,相對來說,後一種方式操作DOM更加可靠。
findDOMNode函式則可以從組建物件中提取dom節點,在有些場景下也可以使用。
2、另外可以考慮使用createPortal函式來優化需要操作dom的場景,該函式一般用於製作react外掛。
#5. 專案中體現經驗的點
對react周期函式的理解深度,掌握每一個函式的特點和應用場景
#6. 論壇參考
https://reactjs.org
#二、 如何實現釋出訂閱模式
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 4星 | Javascript程式設計模式 | 釋出訂閱模式 | Javascript |
#1. 通常解法
利用釋出訂閱模式可以產生更靈活、更鬆散耦合的系統;在實現該模式的關鍵就是理解幾個概念:釋出動作、訂閱動作、訂閱者;
整個流程就是,訂閱動作會使訂閱者監聽某個釋出動作,當訂閱動作執行完畢後,所有的訂閱者都處於監聽狀態;當釋出動作執行後,監聽該釋出動作的所有監聽者都會收到訊號並且自身做出反應;
在以上的例子中,我們可以利用javaScript中的函式去充當一個訂閱者。用一個數組來作為存放所有監聽者的容器。開發一個方法用來模擬訂閱動作,即把訂閱者一次放入容器中,然後在開發一個方法用來模擬釋出動作。即執行容器中的所有 函式;實現如下:
上述程式碼,listen方法就是一個訂閱動作,tigger方法就是有一個釋出動作;
放在list中的所有函式就是訂閱者;當訂閱動作可多次執行,當訂閱動作執行後,訂閱者就處於監聽中。
#2. 通用大牛級解法
在理解了基本的解法和思路之後,我們應該考慮更多的情況和實用性…、
我們改進有以下幾點:
-
要在開發中使用該模式,要做好封裝,採用面向物件的方式
-
要能夠監聽不同的型別;
-
在釋出動作觸發的時候,要能夠給所有的訂閱者傳遞資訊
採用面向物件的方式的話,我們需要確定一個例項中應該有哪些屬性和方法,我們需要一個list屬性用來儲存所有的訂閱者,但是這裡的list不是一個數組,應該是有一個物件,因為我們需要對區分不同型別的訂閱者,該物件中的屬性名將作為訂閱者的型別。還需要有listen方法,該方法用來執行訂閱動作,這裡的訂閱動作不僅新增訂閱者,還需要區分型別,因此會接收兩個引數。一個字串,一個函式。再需要一個釋出動作trigger,該方法需要接收一個字串和一個載荷作為引數,字串決定了觸發何種型別的訂閱者,載荷可以作為傳遞給各個訂閱者的引數;實現如下:
#3. 解法對比及優缺點
釋出者不需要知道訂閱者的數量,訂閱者聽得話題或者訂閱者是通過什麼方式執行的。他們能夠相互獨立地執行,這樣就可以讓你分開開發這兩部分而不需要擔心對狀態或實現的任何細微的影響。、
可擴充套件性
釋出/訂閱模式可以讓系統在無論什麼時候無法負載的時候擴充套件
更乾淨地設計
充分地利用好釋出/訂閱模式,你不得不深入地思考不同的元件是如何互動的。這通常會讓我們有更乾淨地設計因為我們對解耦和鬆耦合的強調。
靈活性
你不需要擔心不同的元件是如何組合在一起的。只要他們共同遵守一份協議
容易測試
你可以很好地找出釋出者或訂閱者是否會得到錯誤的資訊
#4. 延伸及擴充套件問題回答參考
釋出訂閱模式可以解耦程式碼,那麼它 有哪些劣勢呢?
中間人也許不會通知系統訊息傳送的狀態。所以我們無法知道訊息傳送是成功的還是失敗的。緊耦合是需要保證這一點的。
釋出者不知道訂閱者的狀態,反之亦然,這樣的話,你根本不知道在另一端是否會沒有問題?
隨著訂閱者和釋出者數量的增加,不斷增加的訊息傳送回導致架構的不穩定,容易在負載大的時候出問題
攻擊者(惡意的釋出者)能夠入侵系統並且撕開它。這會導致惡意的訊息被髮布,訂閱者能夠獲得他們以前並不能獲得的訊息。
更新發布者和訂閱者的關係會是一個很難的問題,因為畢竟他們根本不認識對方。
需要中間人/代理商,訊息規範和相關的規則會給系統增加一些複雜
#5. 專案中體現經驗的點
關聯行為場景,需要注意的是,關聯行為是可拆分的,而不是“組合”關係。
事件多級觸發場景。
跨系統的訊息交換場景,如訊息佇列、事件匯流排的處理機制
#三、 封裝一個全域性的模態框
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 4星 | 面向物件 | javaScript | 單例模式 |
#1. 通常解法
使用面向物件的方式,把模態框的行為模擬成一個類。在需要的時候例項好化該類,以達到該效果。具體在該類中,應該有生成模態框的html的方法。還需要有控制該模態框顯示和隱藏的方式;這樣的話全域性就僅有一個模態框,以達到封裝的目的;
實現程式碼如下:
#2. 通用大牛級解法
以上述思路為基礎,我們發現有個問題,每次例項化的時候都會生成新的例項,同時也會給頁面新增模態框,造成效能浪費;因此我們可以使用單例模式來解決上述問題,及該類智慧例項化出一個物件;實現程式碼如下:
#3. 解法對比及優缺點
單例模式讓我們在也面中的模態框有且僅有一個,而且如果在頁面中沒有彈出模態框的操作的話,根本不會例項化。在有彈出模態框操作的時候才會例項化,且僅僅是一次。在一定程度上優化來了效能;
#4. 延伸及擴充套件問題回答參考
什麼是單例模式,是什麼惰性單例?
單例模式的定義:保證一個類僅有一個例項,並提供一個訪問他的全域性訪問點
單例模式的核心:是確保只有一個例項,並提供全域性訪問
惰性單例:在需要的時候才建立的物件例項
用途:在頁面中有兩個按鈕,點選的時候需要顯示響應彈窗並載入相應的css檔案
#5.專案中體現經驗的點
在js中,我們經常會把全域性變數當做單例模式來使用,例如:
var a={};
1為什麼a可以當做全域性變數來使用呢,因為其滿足以下兩個條件:
1、物件a獨一無二
2、a定義在全域性作用域下,提供了全域性訪問
注:但是在js中建議使用名稱空間,來減少全域性變數的數量
#6.論壇參考
https://blog.csdn.net/wangxiuyan0228/article/details/79457538
https://www.cnblogs.com/haorui/p/3583337.html
https://blog.csdn.net/victor_e_n_01185/article/details/72875669
#四、 如何解決vue元件之間的通訊?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
80% | 4星 | Vue框架 | 元件通訊 | 資料管理 |
#1. 通常解法
在元件當中藉助第三方外掛 vue-bus
首先基於node下載vue-bus的依賴包:
npm install vue-bus
結合一個模組系統使用時,你需要通過Vue.use()來安裝這個匯流排:
import Vue from 'vue';
import VueBus from 'vue-bus';
Vue.use(VueBus);
具體使用方法如下:
監聽並清除
觸發
#2. 通用大牛級解法
- 父傳子
props
子傳父$emit
- 跨級傳值 provider
- 掛載到全域性 Vue上
- 同域儲存到cookie
- 同級頁面使用釋出訂閱模式
- 大型專案使用vuex
使用vuex
實現元件之間資料的共享。
首先基於node
下載vuex
的依賴包:
npm install vuex --save-dev
你需要通過Vue.use()來安裝這個匯流排,然後例項化Vuex.Store()
import Vue from "vue"
import Vuex from "vuex"
Vue.use( Vuex )
export default new Vuex.Store({})
具體使用方法如下:
定義:
state:存放狀態 getters:計算屬性 mutations:更改state的方法 actions:提交mutations
import Vue from "vue"
import Vuex from "vuex"
Vue.use(Vuex)
export default new Vuex.Store({
state: {userInfor: ''},
getters: {
GetUserInfor: (state) => {
return state.userInfor
},
},
mutations: {
SET_USET_INFOR: (state, userInfor) => {
state.userInfor = userInfor
}
},
actions: {
SetUserInfor: ({state, commit}, config) => {
commit(`SET_USET_INFOR`, config)
}
}
})
使用
computed:{
userInfor: ()=>{
return this.$store.getters.GetUserInfor //獲取資料
}
},
methods: {
setUserInfor () {
this.$store.dispatch('SetUserInfor',{
name:’小明’,
age:12
}) //修改資料
},
}
#3. 解法對比及優缺點
vue-bus與vuex相比,各有各的優勢,針對專案的不同可以選擇對應的方案
1、 vue-bus的通訊機制沒有模組概念,如果管理內容過多容易混亂,而vuex針對於不同的業務需求可以對資料進行模組管理 。
2、 vue-bus主要是事件通訊機制,而vuex則是狀態管理針對於專案中的整個資料進行統一管理,劃分比較明確。
3、 vue-bus理解使用起來比較簡單,但是後期維護起來比較麻煩,容易造成命名衝突,而vuex則理解起來比較複雜,但是後期專案維護比較清晰。
4、 vue-bus適合坐簡單專案中的元件通訊機制,而vuex則比較適合做大型管理類專案
#4. 專案中體現經驗的點
資料操作較多的大型專案
#五、 在主流的vue或react專案中跟後端的資料互動問題?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
80% | 4星 | 專案架構 | 後端互動 | 資料請求 |
#1. 通常解法
目前主流的資料請求方式有兩種
-
axios第三方包,npm下載之後 直接使用
-
fetch請求方式,考慮瀏覽器相容問題 也需要下載第三方包。
使用方式 將下載好的包直接在元件邏輯內呼叫資料請求方法,然後獲取資料之後進行資料操作
#2. 通用大牛級解法
考慮到大型專案中會有多處跟後端的資料互動所以總結出幾點
-
重複呼叫一個介面時會造成很多冗餘程式碼
-
沒有合理的邏輯api封裝會造成程式碼過亂不容易維護
-
沒有完整的資料請求方法呼叫起來會比較複雜
應該根據專案業務需求封裝符合專案邏輯的一些公用請求方法如 request.js
將請求介面的方法封裝為api.js檔案
在專案的元件層只能通過呼叫action動作或者 api檔案內的請求方法來實現跟後端的資料互動
#3. 解法對比及優缺點
本題考核的主要是對專案的資料互動方面的問題。
通用的解法只能滿足專案的需求,不能實現對專案後期維護的考慮
大牛解法考慮後期專案維護及新開發人員加入時的便利性
#4. 延伸及擴充套件問題回答參考
對後端請求邏輯的理解,比如請求頭資訊,及後端返回資料後對資料的批量處理
#5. 專案中體現經驗的點
請求頭,資料過濾,公用邏輯封裝。
#6. 論壇參考
https://www.jianshu.com/p/df464b26ae58
#六、 你是如何解決前端開發資料作用域問題?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | 前端 | 資料通訊 | 資料通訊 |
#1. 通常解法
通過前端瀏覽器儲存;
比如cookie
,sessionstorage
,localstortage,
等前端儲存方式;
Sessionstorage.setItem(“userid”,”12345”)
#2. 通用大牛級解法
把上面的解法說一遍………
使用全域性資料中心,比如flux
,redux
等前端全域性資料中心思想;
實現原理,觀察者模式加全域性資料中心;
import Store from "../tool/flux"
// 全域性資料中心
let initState={
num:1
}
export let actions={
addNum(text){
return {
type:"addNum",
text:text
}
}
}
let reducer = (state = initState, action) => {
switch (action.type) {
case 'addNum':{
let num=state.num+1
return {...state,...{num}}
}
default:
return state
}
}
export default new Store({
state:initState,
reducer
})
#3. 延伸及擴充套件問題回答參
前端儲存的優缺點
前端儲存的優點是:操作簡單,api易學,進行資料的操作隨意性比較大;方便在前端任何領域進行通訊;
前端儲存的缺點則是:
對於資料的儲存量有限,不利於大量資料的儲存,對於資料的讀寫能力一般,不如直接操作js物件
前端全域性資料中心與前端儲存相比,無疑更為先進、方便和可靠。更利於資料的操作等等
#4. 專案中體現經驗的點
問題:flux架構思想,前端資料流,前端mvc思想
解答:
1、基於前端資料互動混亂,以及資料追蹤困難等問題提出的思想
2、基於元件化開發,導致出現了資料通訊問題
3、前端mvc思想,是仿照傳統的服務端mvc進行改進而成,實現檢視,控制層和資料邏輯層的分離,方便資料的追蹤
專案中體現經驗的點
做過元件化開發,主要體現接觸過客戶端服務端分離開發的經驗,適合大多中級工程師必須掌握的知識點
#5. 論壇參考
http://www.redux.org.cn/
https://cnodejs.org/topic/56599f64b31692e827fdcf96
#七、 什麼是同源策略
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 4星 | 前端 | 資料安全 | 資料安全 |
#1. 通常解法
同源策略(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。
現在所有支援JavaScript 的瀏覽器都會使用這個策略。
所謂同源是指,域名,協議,埠相同。
當一個瀏覽器的兩個tab頁中分別開啟來 百度和谷歌的頁面
當瀏覽器的百度tab頁執行一個指令碼的時候會檢查這個指令碼是屬於哪個頁面的,
即檢查是否同源,只有和百度同源的指令碼才會被執行。 [1]
如果非同源,那麼在請求資料時,瀏覽器會在控制檯中報一個異常,提示拒絕訪問。
#2. 通用大牛級解法
加上通用解法後
它的精髓很簡單:它認為自任何站點裝載的信賴內容是不安全的。當被瀏覽器半信半疑的指令碼執行在沙箱時,它們應該只被允許訪問來自同一站點的資源,而不是那些來自其它站點可能懷有惡意的資源。
為什麼要有同源限制?
我們舉例說明:比如一個黑客程式,他利用IFrame把真正的銀行登入頁面嵌到他的頁面上,當你使用真實的使用者名稱,密碼登入時,他的頁面就可以通過Javascript讀取到你的表單中input中的內容,這樣使用者名稱,密碼就輕鬆到手了。
Ajax應用:
在Ajax應用中這種安全限制被突破。
在普通的Javascript應用中,我們可以修改Frame的href,或者IFrame的src,以實現GET方式的跨域提交,但是卻不能訪問跨域的Frame/IFrame中的內容。
而Ajax它通過XMLHTTP進行非同步互動,這個物件同樣能夠與遠端的伺服器進行資訊互動,而且更加危險的是,XMLHTTP是一個純粹的Javascript物件,這樣的互動過程,是在後臺進行的,不被使用者察覺。因此,XMLHTTP實際上已經突破了原有的Javascript的安全限制。
如果我們又想利用XMLHTTP的無重新整理非同步互動能力,又不願意公然突破Javascript的安全策略,可以選擇的方案就是給XMLHTTP加上嚴格的同源限制。這樣的安全策略,很類似於Applet的安全策略。IFrame的限制還僅僅是不能訪問跨域HTMLDOM中的資料,而XMLHTTP則根本上限制了跨域請求的提交。
瀏覽器支援:
而IE其實給這個安全策略開了兩個想當然的後門,一個是:他假設你的本地檔案,自然清楚將會訪問什麼內容,所以任何你的本地檔案訪問外部資料, 都不會收到任何的警告。另一個是:當你訪問的網站指令碼打算訪問跨域的資訊時, 他居然僅僅是彈出一個對話方塊來提醒你一下。如果一個欺詐網站,採用這樣的手 段,提供一個假頁面給你,然後通過XMLHTTP幫你遠端登入真實的銀行伺服器。只要10個使用者裡,有一個使用者糊塗一下,點了一個確定。他們的盜取帳號行為,就成功了! 你想想看,這是何等危險的事情! FireFox就不是這樣的做法,預設的情況下,FireFox根本就不支援跨域的XMLHTTP請求,根本就不給黑客這樣的機會。
避免同源策略:
JSON和動態指令碼標記
<script type="text/javascript"
src="http://travel.com/findItinerary?username=sachiko& reservationNum=1234&output=json&callback=showItinerary" />
當 JavaScript 程式碼動態地插入<script>
標記時,瀏覽器會訪問 src 屬性中的 URL。這樣會導致將查詢字串中的資訊傳送給伺服器。在 清單 1中,所傳遞的是 username 和 reservation 作為名稱值對傳遞。此外,查詢字串還包含向伺服器請求的輸出格式和回撥函式的名稱(即 showItinerary)。<script>
標記載入後,會執行回撥函式,並通過回撥函式的引數把從服務返回的資訊傳遞給該回調函式。
Ajax代理
Ajax 代理是一種應用級代理伺服器,用於調解 Web 瀏覽器和伺服器之間的 HTTP 請求和響應。Ajax 代理允許 Web 瀏覽器繞過同源策略,這樣便可以使用 XMLHttpRequest 訪問第三方伺服器。要實現這種繞過,有如下兩種方法可供選擇:
· 客戶端 Web 應用程式知道第三方 URl並將該 URl作為 HTTP 請求中的一個請求引數傳遞給 Ajax 代理。然後,代理將請求轉發給 www.remoteservice.com。注意,可以把代理伺服器的使用隱藏在 Web 應用程式開發人員所使用的 Ajax 庫的實現中。對於 Web 應用程式開發人員而言,它看上去可能完全不具有同源策略。
客戶端 Web 應用程式不知道第三方 URL,並且嘗試通過 HTTP 訪問 Ajax 代理伺服器上的資源。通過一個預定義的編碼規則,Ajax 代理將 所請求的 URl轉換為第三方伺服器的 URl並代表客戶檢索內容。這樣一來,Web 應用程式開發人員看上去就像是在和代理伺服器直接進行通訊。
#3. 解法對比及優缺點
通常解法,僅就問題本身做簡要解答,未能夠對問題做詳盡分析及解決。通用級解法,將同源策略的應用範圍和應用場景,都有詳細的介紹,進一步說明對此問題的深度理解。
#4. 延伸及擴充套件問題回答參考
問題: 接觸到的前端同源策略的問題都有哪些?
解答:
(1) Cookie、LocalStorage 和 IndexDB 無法讀取。
(2) DOM 無法獲得。
(3) AJAX 請求不能傳送。
問題:同源策略問題?
解答:
1、 iframe
2、 window.name
3、 window.postMessage
#5. 專案中體現經驗的點
當在專案中,解決資料的儲存以及獲取,還有通訊時,經常遇到的問題;使用頻率比較高
#6. 論壇參考
http://www.360doc.com/content/17/0925/20/47820059_690133713.shtml
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
https://blog.csdn.net/tim_tsang/article/details/46124527
#八、 Generator async promise 的區別?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | Es6 | 非同步 | Es6非同步操作 |
#1. 通常解法
Generator async promise 這三個api都是es6新增api,
Generator 函式定義需要通過*來定義,通過yield表示式定義不同的狀態,呼叫的時候需要使用next()進行狀態的變更,直到遇到return後才能終止
Async是Generator函式的語法糖,也就是簡寫,但是Async中定義狀態使用await定義狀態,執行的時候不需要next,自動執行,並且async是結合promise一起使用的,await 的結果可以自動獲取promise的resolve值
Promise是為了解決之前利用回撥函式進行非同步呼叫的解決方法,promise可以使用鏈式呼叫的方式得到成功的回撥,並且可以在返回一個promise繼續呼叫,
在promise中有3個狀態進行中,成功,失敗,可以使用resolve,reject,手動控制成功失敗的回撥
#2. 通用大牛級解法
Generator async promise 這三個api都是es6新增api,也都可以理解為非同步的解決方案,但是他們的適用場景不一樣
#Generator:
簡單點可以把它理解成,Generator 函式是一個狀態機,封裝了多個內部狀態。
執行 Generator 函式會返回一個遍歷器物件,也就是說,Generator 函式除了狀態機,還是一個遍歷器物件生成函式。返回的遍歷器物件,可以依次遍歷 Generator 函式內部的每一個狀態。
形式上,Generator 函式是一個普通函式,但是有兩個特徵。一是,function關鍵字與函式名之間有一個星號;二是,函式體內部使用yield表示式,定義不同的內部狀態
而Generator在適用場景上我們可以把它理解為任務的掛起,在js中我們使用沒有任務掛起這個概念的,直到Generator的出現,在Generator的使用上我們通過yield定義不同的狀態,執行的時候需要使用next進行不同狀態的呼叫,但是他是從上到下的,也就是隻要需要yield就會停止執行後面的語句,呼叫next後繼續執行後面的語句,在實際專案開發中,我經常會遇到這樣的需求,填寫使用者資訊的時候一般都是分成幾步,這時候我們就可以利用Generator的任務掛起特性進行,不同步驟的資料儲存。
#promise
promise解決了傳統非同步操作回撥函式更加合理強大,有了promise就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。此外,Promise物件提供統一的介面,使得控制非同步操作更加容易。
例如我常見的一個需求
有兩個介面A,B, 他們之間有依賴關係,B介面必須等到A介面的值返回成功後,拿到A接口裡面的一個屬性才能請求,如果利用之前的回撥函式形勢的話就得是層層巢狀,程式碼維護比較麻煩,如果利用promise的話我們可以用鏈式呼叫的形勢直觀的表示出這種關係
#Async和Generator
而Async是Generator函式的語法糖,Async的出現主要是為了解決另外一個問題,剛剛說了Generator是解決任務的掛起,promise是解決非同步回撥問題,而async就是吧非同步的操作,變成佇列模式,
因為async中使用await做狀態的定義,呼叫的時候不需要next(),自動執行,並且會講每個await中promise中resolve結果賦值給await的變數上以供後面的步驟使用,每一個await都會等到promise返回結果後才會繼續自動往下執行,這樣就實現了我在日常生活中排隊執行的概念,將所有的非同步任務以同步的方式定義,不需要擔心那個快那個慢,因為她是一個一個自動向下的
#3. 解法對比及優缺點
綜上所述:第一種只是說出了 Generator async promise如何使用,而第二種說出了執行原理,存在的意義,適用的場景
#4. 延伸及擴充套件問題回答參考
問題: 如何合併多個請求,
解答:使用promise.all可以將多個使用promise定義的ajax請求合併處理
#5. 專案中體現經驗的點
對於 Generator async promise正確的使用,利用它們不同的優點,實現不同的業務需求
#6. 論壇參考
http://es6.ruanyifeng.com/#docs/promise
http://es6.ruanyifeng.com/#docs/generator
http://es6.ruanyifeng.com/#docs/async
#九、 說一下前端儲存?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 4星 | Javascript | 資料儲存 | 儲存 |
#1. 通常解法
Cookie技術瀏覽器相容性好,但操作比較複雜,需要程式設計師自己封裝,源生的Cookie介面不友好, 儲存的內容較小, cookie的資料會隨著ajax的請求傳送到服務端,一般情況主要用在使用者登入的時候我們可以通過在 Cookie 中存入一段辨別使用者身份的資料,用於後臺判斷。
WebStorage則不能超過8MB,操作簡單;可以代替一些cookie的工作,一般主要是用於儲存一些本地資料,購物車資料之類的在安全方面的話,都不安全,一般就是對資料進行一些簡單的加密,如base64編碼,加密約定之類的東西localstorage、sessionstorage一個是長期儲存,一個是會話儲存
。
#2. 通用大牛級解法
常用瀏覽器儲存方案有,cookie,session,localstorage,sessionstroage
#cookie
cookie 本身不是用來做伺服器端儲存的,它是設計用來在伺服器和客戶端進行資訊傳遞的,因此我們的每個 HTTP 請求都帶著 cookie。但是 cookie 也具備瀏覽器端儲存的能力(例如記住使用者名稱和密碼,也就是常用的登入功能),因此就被開發者用上了。
使用起來也非常簡單,document.cookie = ....即可。
但是 cookie 有它致命的缺點:
儲存量太小,只有 4KB
所有 HTTP 請求都帶著,會影響獲取資源的效率
API 簡單,需要封裝才能用
所有的api請求都會攜帶cookie,所以cookie不太安全,使用的時候一般都需要做加密處理
#session
session是服務端的會話儲存技術,他的生存週期只是保持在瀏覽器開啟,瀏覽器關閉這個階段之中
在Session被建立之後,就可以呼叫Session相關的方法往Session中增加內容了,而這些內容只會儲存在伺服器中,發到客戶端的只有Session id;當客戶端再次傳送請求的時候,會將這個Session id帶上,伺服器接受到請求之後就會依據Session id找到相應的Session,從而再次使用之。正式這樣一個過程,使用者的狀態也就得以保持了。
在使用session的時候我們一般都儲存一些臨時資料,常見的需求一般就是獲取驗證碼
#locationStorage 和 sessionStorage
後來,HTML5 標準就帶來了sessionStorage和localStorage,先拿localStorage來說,它是專門為了瀏覽器端快取而設計的。其優點有:
儲存量增大到 5MB
不會帶到 HTTP 請求中
API 適用於資料儲存
localStorage.setItem(key, value)
localStorage.getItem(key)
sessionStorage的區別就在於它是根據 session 過去時間而實現,而localStorage會永久有效,應用場景不同。例如,一些需要及時失效的重要資訊放在sessionStorage中,一些不重要但是不經常設定的資訊,放在localStorage中。
但是sessionstroage有個致命的缺點,就是無法多標籤頁共享。
#3. 解法對比及優缺點
通常解法,解釋了cookie,本地儲存的用法。通用級解法,不僅僅講解了用法,還說出了其執行原理,以及不同技術之間的使用場景
#4. 延伸及擴充套件問題回答參考
問題: sessionstroage如何實現多標籤頁面資料共享
#5. 專案中體現經驗的點
登入判斷,本地資料線上資料的同步。
#6. 論壇參考
https://www.cnblogs.com/lonelydreamer/p/6169469.html
https://www.cnblogs.com/andy-zhou/p/5360107.html
#十、 解釋一下javaScript中的垃圾回收機制?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | Js底層原理 | javaScript | 釋出訂閱 |
#1. 通常解法
javaScript具有自動垃圾收集機制,也就是說,執行環境會負責管理程式碼執行過程中使用的記憶體。而在C和C++之類的語言中,開發人員的一項基本任務就是手工跟蹤記憶體的使用情況,這是造成許多問題的一個根源。在編寫javaScript程式時,開發人員不用關心記憶體使用問題,所需記憶體的分配以及無用記憶體的回收完全實現了自動管理。這種垃圾收集機制的原理其實很簡單:找出那些不再繼續使用的變數,然後釋放其佔用的記憶體。為此,垃圾收集器會按照固定的時間間隔(或程式碼執行中預定的收集時間),週期性的執行這一操作;
如上圖:javaScript操作的資料在記憶體中是這樣儲存的,當某塊記憶體中儲存的資料無用時,那麼就要遵守javaScript的記憶體回收機制將這些空閒記憶體回收,以供重新分配;
#2. 通用大牛級解法
在通用解法的基礎上,我們分一下函式中區域性變數的生命週期。區域性變數只在函式執行的過程中存在。而在這個過程中,會為區域性變數在棧(或堆)記憶體上分配相應的空間,以便儲存他們的值。然後在函式中使用這些變數,直至函式執行結束。此時,區域性變數就沒有存在的必要了,因此可以釋放它們的記憶體以供將來使用。在這種情況下,很容易判斷變數是否還有存在的必要;但並非所有情況下都這麼容易就能得出結論。垃圾收集器必須跟蹤哪個變數有用哪個變數沒有,對於不再有用的變數打上標記,以備將來收回其佔用的記憶體。用於表示無用變數的策略可能會因實現而異,但具體到瀏覽器中的實現通常有兩個策略。分別是標記清除和引用計數
標記清除
javaScript中最常用的垃圾收集方式是標記清除(mark-and-sweep)。當變數進入環境時,就將這個變數標記為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變數所佔用的記憶體,因為只要執行流進入相應的環境,就可能會用到它們。而當變數離開環境時,則將其標記為“離開環境”。
垃圾收集器在執行的時候會給儲存在記憶體中的所有變數都加上標記。然後,它會去掉環境中的變數以及被環境中的變數引用的變數標記。而在此之後再被加上標記的變數將被視為準備刪除的變數,原因是環境中的變數已經無法訪問到這些變量了。最後,垃圾收集器完成記憶體清除工作,銷燬那些帶標記的值並回收他們所佔用的記憶體空間。
引用計數
另一種不太常見的垃圾收集策略叫做引用計數。引用計數的含義是跟蹤記錄每個值被引用的次數。當聲明瞭一個變數並將一個引用型別賦值給該變數時,則這個值的引用此時就是1。如果同一個值又被賦給另一個變數,則該值的引用次數加1。相反,如果包含對這個值引用的變數又取得了另外一個值,則這個值的引用次數減1。當這個值的引用次數變成0是,則說明沒有辦法再訪問這個值了,因而就可以將其佔用的記憶體空間回收回來。這樣,當垃圾收集器下次再執行時,它就會釋放那些引用次數為零的值所佔用的記憶體。
#3. 解法對比及優缺點
對比以上解法,可以掌握以下幾點:
基本型別值在記憶體中佔據固定大小的空間,因此被儲存在棧記憶體中;
從一個變數向另一個變數複製基本資料型別的值,會建立這個值的一個副本;
引用型別的值是物件,儲存在堆記憶體中;
包含引用型別值的變數實際上包含的並不是物件本身,而是一個指向該物件的指標;
當代碼中存在引用計數的策略時,迴圈引用會導致問題;
#4. 延伸及擴充套件問題回答參考
根據垃圾回收機制來思考,如何管理記憶體;
使用具備垃圾收集機制的語言編寫程式,開發人員一般不必操心記憶體管理問題。但是,javaScript在進行記憶體管理及垃圾回收時面臨的問題還是有點與眾不同。其中最主要的一個問題,就是分配給web瀏覽器的可用記憶體數量通常比分配給桌面應用程式的少。這樣做的目的主要是出於安全方面的考慮,目的是防止執行javaScript的網頁耗盡全部系統記憶體而導致系統崩潰。記憶體限制問題不僅會影響給變數分配記憶體,同時還會影響呼叫棧以及在一個執行緒中能夠同時執行的語句數量。
因此,確保佔用最少的記憶體可以讓頁面獲得更好的效能。而優化記憶體佔用的最佳方式,就是為執行中的程式碼只儲存必要的資料。一旦資料不再有用,最好通過將其值設定為null來釋放其引用---這個叫做接觸引用。這一做法適用於大多數全域性變數和全域性物件的屬性。區域性變數會在它們離開執行環境時自動被解除引用。
#5. 專案中體現經驗的點
深刻理解垃圾回收機制,主要程式碼的規範和書寫方式,儘量避免記憶體洩露的問題;
#6. 論壇參考
https://www.jb51.net/article/75292.htm
https://blog.csdn.net/Christine95/article/details/50877645
https://blog.csdn.net/IamChuancey/article/details/78452366
#十一、 解釋一下React中的JSX語法?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
75% | 3星 | 虛擬DOM | 開發效率 | js |
#1. 通常解法
JavaScript eXtension
,或更常見的JSX,是一個React擴充套件,允許我們編寫看起來像 HTML的JavaScript 。
可以在 JSX 中使用 JavaScript 表示式。表示式寫在花括號 {} 中;
在 JSX 中不能使用 if else 語句,但可以使用 conditional (三元運算) 表示式來替代;
React 推薦使用內聯樣式。我們可以使用 camelCase 語法來設定內聯樣式. React 會在指定元素數字後自動新增 px;
JSX 允許在模板中插入陣列,陣列會自動展開所有成員;
JSX事件繫結使用駝峰寫法,比如
<div onClick={()=>{}}></div>
1#2. 通用大牛級解法
雖然JSX看起來像HTML,但它實際上只是React.createElement()的語法糖。當元件渲染時,它輸出一個React元素樹或該元件輸出的HTML元素的虛擬表示。React然後將基於此React元素表示來確定對實際DOM所做的更改。
例如:
class Header extends React.Component {
render() {
return (
<h1>Hello World</h1>
);
}
}
其實對應於
class HelloWorld extends React.Component {
render() {
return (
React.createElement(
'h1',
{className: 'large'},
'Hello World'
)
);
}
}
就是說JSX最終會被babel等編譯工具轉換為普通的JS來讓瀏覽器識別,而轉換的結果是React.createElement()函式,該函式不會生成真實的DOM而是建立一個虛擬DOM,虛擬DOM本身就是一個物件。ReactDOM.render()將虛擬DOM渲染到檢視上,會經過diff運算以減小不必要的DOM操作,從而提高頁面效能。
#3. 解法對比及優缺點
普通解法只是概括jsx表面特點,以及如何使用。
大牛級解法對jsx的實質作了進一步闡述,充分體現開發人員對jsx語法的理解
#4. 延伸及擴充套件問題回答參考
虛擬DOM的概念被react框架發明,得到了社群的積極響應,目前主流應用框架都引入了虛擬DOM的概念,比如VUE也通過虛擬DOM+diff運算來提升頁面效能
#5. 專案中體現經驗的點
深刻理解JSX語法的特點和原理;
#6. 論壇參考
http://www.runoob.com/react/react-jsx.html
https://blog.csdn.net/tianzhw/article/details/78812475
https://www.cnblogs.com/zourong/p/6043914.html
#十二、 redux三大原則?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
85% | 4星 | 資料管理 | 跨組建通訊 | reducers |
Redux 可以用這三個基本原則來描述:
#1. 單一資料來源
整個應用的state被儲存在一棵 object tree中,並且這個 object tree只存在於唯一一個store中。
這讓同構應用開發變得非常容易。來自服務端的 state 可以在無需編寫更多程式碼的情況下被序列化並注入到客戶端中。由於是單一的 state tree ,除錯也變得非常容易。在開發中,你可以把應用的 state 儲存在本地,從而加快開發速度。此外,受益於單一的 state tree ,以前難以實現的如“撤銷/重做”這類功能也變得輕而易舉。
console.log(store.getState())
//Prints
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
12
3
4
5
6
7
8
9
10
11
12
13
14
15
#2. State 是隻讀的
惟一改變 state 的方法就是觸發action,action 是一個用於描述已發生事件的普通物件。
這樣確保了檢視和網路請求都不能直接修改 state,相反它們只能表達想要修改的意圖。因為所有的修改都被集中化處理,且嚴格按照一個接一個的順序執行,因此不用擔心 race condition 的出現。 Action 就是普通物件而已,因此它們可以被日誌列印、序列化、儲存、後期除錯或測試時回放出來。
store.dispatch({
type: 'COMPLETE_TODO',
index: 1
});
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
});
#3. 使用純函式來執行修改
為了描述 action 如何改變 state tree ,你需要編寫reducers。
Reducer 只是一些純函式,它接收先前的 state 和 action,並返回新的 state。剛開始你可以只有一個 reducer,隨著應用變大,你可以把它拆成多個小的 reducers,分別獨立地操作 state tree 的不同部分,因為 reducer 只是函式,你可以控制它們被呼叫的順序,傳入附加資料,甚至編寫可複用的 reducer 來處理一些通用任務,如分頁器。
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
text: action.text,
completed: false
}
]
case 'COMPLETE_TODO':
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: true
})
}
return todo
})
default:
return state
}
}
import { combineReducers, createStore } from 'redux'
let reducer = combineReducers({ visibilityFilter, todos })
let store = createStore(reducer)
#十三、 redux-saga中介軟體?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
40% | 5星 | redux中介軟體 | 非同步流程管理了 | 資料容器 |
#1. 通常解法
Saga是一個可以用來處理複雜的非同步邏輯的模組,並且由redux的action觸發,Saga副作用就是在action觸發reducer之後執行的一些動作, 這些動作包括但不限於,連線網路,io讀寫,觸發其他action。並且,因為Saga的副作用是通過redux的action觸發的,每一個action,saga都會像reducer一樣接收到。並且通過觸發不同的action, 我們可以控制這些副作用的狀態, 例如,啟動,停止,取消。通常配置Saga中介軟體由2部分組成:worker saga和watcher saga。watcher saga用於訂閱action,worker saga用於根據action執行相應的操作。
所有的saga都是基於ES6的generator,generator函式可以將非同步邏輯轉為同步邏輯來編寫。
例如:
watcher saga:function* watch(){
yield takeEvery(‘action type’, worker saga);
}
worker saga: function* worker(){
yield call()
yield put()
};
#2. 通用大牛級解法
Saga可以實現複雜非同步流程管理,適合在大型專案且業務場景複雜的情況下使用。在業務邏輯層,可以簡化程式碼,使程式碼更加容易閱讀。 在重用方面,解耦顯示層和業務層之後, 程式碼的重用度也得到了提升。使用基礎API如take, put, call, fork, all等可以實現多流程控制,包括順序執行,並行執行和競爭執行等。相比於redux-thunk中介軟體只是實現非同步流程控制反轉dispatch(function)來說,避免了難以測試的問題,邏輯流程也更加清晰。
Saga的應用簡單總結來說就是:
檢視=>dispatch(action)=>saga中介軟體:訂閱action(watcher)+ worker + dispatch(action)=>資料容器redux(reducer)。
雖然saga可以起很大的效果,但是也有弊端:
redux-saga模型的理解和學習需要投入很多精力
因為需要用action觸發,所以會產生很多對於reducer無用的action, 但是reducer一樣會跑一輪,雖然目前沒有觀測到效能下降,但還是有計算開銷
在action的定義上要謹慎,避免action在saga和reducer之間重複觸發,造成死迴圈
增加了專案目錄結構複雜度和維護成本
#3. 解法對比及優缺點
普通解法只是對redux-saga基本使用的介紹,僅限於知道怎麼用,不能說明redux-saga的適用場景,以及更復雜場景的使用情況。
大牛解法則清楚地說明了redux-saga的應用流程,心裡明確什麼時候需要使用saga。並且對潛在問題做了說明,同時對比了其他類似的中介軟體,體現了豐富的應用經驗
#4. 延伸及擴充套件問題回答參考
對比說明redux-saga和redux-thunk的特點?
越是用來解決具體問題的技術,使用起來越容易,越高效,學習成本越低;越是用來解決寬泛問題的技術,使用起來越難,學習成本越高。 thunk解決的是很具體的一個問題,就是在action到達reducer之前做一些其他的業務,比如fetch後端, 它在做這件事的上很高效。而Saga解決的問題要更寬泛一些,因為saga只是攔截了action,至於做什麼,開發者需要自己來考慮,可以是fetch後端,也可以是更新redux store, 甚至可以執行action帶進來的callback。 很顯然對於一個業務層來說,saga會是一個更合適的選擇,但同時也帶來了學習成本的提高。
#5. 專案中體現經驗的點
深刻理解專案非同步流程管理問題,以及選擇正確的解決方案;
#6. 論壇參考
https://redux-saga-in-chinese.js.org/docs/api/
https://www.jianshu.com/p/89ed2a01a3db
#十四、 react-redux中的容器元件(container)和展示元件(component)?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 3星 | 全域性狀態管理 | 狀態管理 | redux |
react-redux的作用是連線(connect)store和容器元件的。store是redux提供的,容器元件是react提供的。
#1. 組織應用的元件
組織應用的元件
o 容器元件
o 展示元件
容器元件:位於應用最頂層的元件,用來與redux連線的。從redux中獲取資料作為props。
展示元件:位於應用的中間或者子元件,是純粹的元件,與redux沒有關係。他們從自己的父元件獲取資料作為props,他們的共同根元件是應用的唯一的容器元件。展示元件可以維持少量的自身狀態資訊。
#2. 連線Store與元件
react-redux僅僅提供兩個關鍵模組:Provider和connect。
原始碼:
import Provider from './components/Provider'
import connect from './components/connect'
export { Provider, connect }
· Provider:是一個元件,接受一個store屬性和一個子元件(也就是上面說到的:store是redux提供的,容器元件是是react提供的。)
#3. 通常解法
ReactDOM.render(
<Provider store={store}>
<Handler routerState={routerState} />
</Provider>,
document.getElementById('root')
);
· connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options]):connect返回一個函式,它接受一個React元件的建構函式作為連線物件,最終返回連線好的元件建構函式。
import * as actionCreators from './actionCreators'
function mapStateToProps(state) {
return { todos: state.todos }
}
export default connect(mapStateToProps, actionCreators)(MyRootComponent)
#
#十五、 簡述前端效能優化的措施?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 4星 | 效能優化 | javaScript | 效能優化 |
#1. 通常解法
從網路載入方面來考慮
減少HTTP請求次數
建議儘可能的根據需要去合併靜態資源圖片、JavaScript程式碼和CSS檔案,減少頁面請求數,這樣可以縮短頁面首次訪問的等待時間,另外也要儘量的避免重複資源,防止增加多餘的請求
減少HTTP請求大小
除了減少請求資源數,也要減少每個http請求的大小。比如減少沒必要的圖片,JS,CSS以及HTML等,對檔案進行壓縮優化,開啟GZIP壓縮傳輸內容,縮短網路傳輸等待延遲
將CSS和JS放到外部檔案中,避免使用style和script標籤引入
在HTML檔案中引入外部的資源可以有效利用瀏覽器的靜態資源快取。有時候在移動端對請求數比較在意的會為了減少請求把CSS和JS檔案直接寫到HTML裡邊,具體根據CSS和JS檔案大小和業務場景來分析。如果CSS和JS檔案內容較多,邏輯比較複雜,建議放到外部引入
避免頁面中空的href和src
當link標籤的href屬性為空,或者script、img、iframe標籤的src屬性為空的時候,瀏覽器在渲染的過程中還是會把href和src的空內容進行載入,直到載入失敗。這樣就阻塞了頁面中其他資源的下載程序,並且最後載入的內容是無效的,因此要儘量避免。
為HTML指定Cache-Control或者Expires
為HTML指定Cache-Control或者Expires可以將HTML內容快取起來,避免頻繁向伺服器傳送請求。在頁面Cache-Control或Expires頭部又消失,瀏覽器會直接從快取讀取內容,不向伺服器傳送請求
靜態資源不同域名存放
瀏覽器在同一時刻向同一個域名請求檔案的並行下載數是有限的,因此可以理由多個域名的主機來存放不同的靜態資源,增大頁面載入時資源的並行下載數。
使用get請求
POST請求會首先發送檔案頭,然後傳送HTTP正文的資料。而使用GET只發送頭部,所以在拉取資料時使用GET請求效率更高
消除阻塞頁面的CSS和JS
對於頁面中載入時間過長的CSS或JS檔案,需要進行合理的拆分或者延後載入,保證關鍵的資源能快速載入完成
按需載入
#2. 通用大牛級解法
不僅考慮到網路請求方面,同時也考慮到頁面渲染方面
把CSS資源引用放到HTML檔案頂部
這樣瀏覽器可以優先下載CSS並儘快完成頁面渲染
JavaScript檔案引用放到HTML檔案底部
可以防止JavaScript的載入和解析執行對頁面渲染造成阻塞。由於JavaScript資源預設是解析阻塞的,除非被標記為非同步或者通過其他的方式非同步載入,否則會阻塞HTMl DOM解析和CSS渲染過程
不要在HTML中直接縮放圖片
在HTML中直接縮放圖片會導致頁面內容的重排重繪,此時可能會使頁面中的其他操作產生卡頓,因此要儘量減少在頁面中直接進行圖片縮放
減少DOM元素數量和深度
HTML中標籤元素約的,標籤的層級越深,瀏覽器解析DOM並繪製到瀏覽器中說花的時間就越長。
儘量避免使用table、iframe等慢元素
內容的渲染是講table的DOM渲染樹全部生成完並一次性繪製到頁面上,所以在長表格渲染時很耗效能,應該儘量避免使用,可以考慮用ul代替。儘量使用非同步的方式動態的載入iframe,因為iframe內資源的下載程序會阻塞父頁面靜態資源的下載以及HTMl DOM的解析
避免執行耗時的JavaScript
長時間執行的JavaScript會阻塞瀏覽器構建DOM樹、DOM渲染樹、渲染頁面。所以任何與頁面初次渲染無關的邏輯功能都應該延遲載入執行,這和JavaScript資源的非同步載入思路一致
#3. 解法對比及優缺點
前端優化的策略有很多,主要包括網路載入,頁面渲染,CSS優化,JS執行優化,快取,圖片,協議幾大類;
網路請求是影響前端效能的一個主要因素,當然頁面渲染也是一個非常重要的因素;因此我們應該針對這個兩個方面都進行優化;
#4. 延伸及擴充套件問題回答參考
請減少HTTP請求基本原理:
在瀏覽器(客戶端)和伺服器發生通訊時,就已經消耗了大量的時間,尤其是在網路情況比較糟糕的時候,這個問題尤其的突出。
一個正常HTTP請求的流程簡述:如在瀏覽器中輸入"www.xxxxxx.com"並按下回車,瀏覽器再與這個URL指向的伺服器建立連線,然後瀏覽器才能向伺服器傳送請求資訊,伺服器在接受到請求的資訊後再返回相應的資訊,瀏覽器接收到來自伺服器的應答資訊後,對這些資料解釋執行。
而當我們請求的網頁檔案中有很多圖片、CSS、JS甚至音樂等資訊時,將會頻繁的與伺服器建立連線,與釋放連線,這必定會造成資源的浪費,且每個HTTP請求都會對伺服器和瀏覽器產生效能負擔。
網速相同的條件下,下載一個100KB的圖片比下載兩個50KB的圖片要快。所以,請減少HTTP請求。
解決辦法:
合併圖片(css sprites),合併CSS和JS檔案;圖片較多的頁面也可以使用 lazyLoad 等技術進行優化。
請正確理解 Repaint 和 Reflow
基本原理:
Repaint(重繪)就是在一個元素的外觀被改變,但沒有改變佈局(寬高)的情況下發生,如改變visibility、outline、背景色等等。
Reflow(重排)就是DOM的變化影響到了元素的幾何屬性(寬和高),瀏覽器會重新計算元素的幾何屬性,會使渲染樹中受到影響的部分失效,瀏覽器會驗證DOM樹上的所有其它結點的visibility屬性,這也是Reflow低效的原因。如:改變窗囗大小、改變文字大小、內容的改變、瀏覽器視窗變化,style屬性的改變等等。如果Reflow的過於頻繁,CPU使用率就會噌噌的往上漲,所以前端也就有必要知道 Repaint 和 Reflow的知識
減少效能影響的辦法:
上面提到通過設定style屬性改變結點樣式的話,每設定一次都會導致一次reflow,所以最好通過設定class的方式; 有動畫效果的元素,它的position屬性應當設為fixed或absolute,這樣不會影響其它元素的佈局;如果功能需求上不能設定position為fixed或absolute,那麼就權衡速度的平滑性。
總之,因為 Reflow 有時確實不可避免,所以只能儘可能限制Reflow的影響範圍。
#5. 專案中體現經驗的點
在操作頁面的dom時,方式很多,但是我們應該從影響前端效能的這個方面著手去解決這個問題,避免過多的重排,操作dom元素不要過深
#6.論壇參考
https://www.cnblogs.com/liulilin/p/7245125.html
https://www.jianshu.com/p/ead7dab72cd6?mType=Group
https://blog.csdn.net/w2326ice/article/details/64122372
#十六、 你是如何解決移動端適配問題?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | 前端 | 移動端適配 | 移動端適配 |
#1. 通常解法
通過百分比進行單位的換算;
通過媒介查詢進行單位的設定;
使用媒介查詢配合rem
@media screen and (min-width:360px) and (max-width:374px) and (orientation:portrait) {
html { font-size: 703%; }
}
@media screen and (min-width:375px) and (max-width:383px) and (orientation:portrait) {
html { font-size: 732.4%; }
}
@media screen and (min-width:384px) and (max-width:399px) and (orientation:portrait) {
html { font-size: 750%; }
}
@media screen and (min-width:400px) and (max-width:413px) and (orientation:portrait) {
html { font-size: 781.25%; }
}
@media screen and (min-width:414px) and (max-width:431px) and (orientation:portrait){
html { font-size: 808.6%; }
}
@media screen and (min-width:432px) and (max-width:479px) and (orientation:portrait){
html { font-size: 843.75%; }
}
#2. 通用大牛級解法
把上面的解法說一遍………
網易手機端
body的width都是7.5rem。很明顯,目前網易的手機端設計稿是基於iPhone6,750(設計師給的設計稿是物理解析度,會是我們寫樣式的邏輯解析度的兩倍,如果給的設計稿是640,那麼是基於iPhone5,320),且基準值是100px(750/7.5=100)。這個基準值很關鍵,後面的css換算,都和這個基準值有關。動態font-size: 我們看到圖1、圖2、圖3的font-size都有根據螢幕大小而動態改變,可以推算出公式:
螢幕寬度/設計稿rem寬度=頁面動態font-size值(如:375/7.5=50)
獲取到這個值,再賦給html元素的style:
document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + ‘px‘;
1這樣就設定好了每個頁面的根fonts-size,因為rem單位是基於根font-size,因此只要確定一種設計稿對應手機的換算,其餘螢幕尺寸均可自動適配。
上面我們得出設計稿換算rem的基準值是100,因此只需要把設計稿上的px值除以100即為我們要的rem值。
Px/100=rem,所以100px=1rem,25px=0.25rem
淘寶手機端
引入: 直接引用阿里的CDN檔案(或下載到本地引入)
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
設定: 頁面不要設定 。Flexible會自動設定每個螢幕寬度的根font-size、動態viewport、針對Retina屏做的dpr。
換算: 假設拿到的設計稿和上述網易的一樣都是750,Flexible會把設計稿分為10份,可以理解為頁面width=10rem,即1rem=75px,所以根font-size(基準值)=75px。
#3. 解法對比及優缺點
通用方案
1、設定根font-size:625%(或其它自定的值,但換算規則1rem不能小於12px)
2、通過媒體查詢分別設定每個螢幕的根font-size
3、css直接除以2再除以100即可換算為rem。
優:有一定適用性,換算也較為簡單。
劣:有相容性的坑,對不同手機適配不是非常精準;需要設定多個媒體查詢來適應不同手機,單某款手機尺寸不在設定範圍之內,會導致無法適配。
網易方案
1、拿到設計稿除以100,得到寬度rem值
2、通過給html的style設定font-size,把1裡面得到的寬度rem值代入x
document.documentElement.style.fontSize = document.documentElement.clientWidth / x + ‘px‘;
3、設計稿px/100即可換算為rem
優:通過動態根font-size來做適配,基本無相容性問題,適配較為精準,換算簡便。
劣:無viewport縮放,且針對iPhone的Retina屏沒有做適配,導致對一些手機的適配不是很到位
手淘方案
1、拿到設計稿除以10,得到font-size基準值
2、引入flexible
3、不要設定meta的viewport縮放值
4、設計稿px/ font-size基準值,即可換算為rem
優:通過動態根font-size、viewpor、dpr來做適配,無相容性問題,適配精準。
劣:需要根據設計稿進行基準值換算,在不使用sublime text編輯器外掛開發時,單位計算複雜。
#4. 延伸及擴充套件問題回答參考
問題:移動端專案對於背景圖的載入
解答: 使用的網易解決方案可以實現雪碧圖的使用;
專案中體現經驗的點
使用網易的解決的方案可以使用的移動端適配更加精確
#5. 論壇參考
https://www.cnblogs.com/liangxuru/p/6970629.html
https://www.cnblogs.com/cench/p/5314044.html
#十七、 談談對node對的看法?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 4星 | 前端 | 資料安全 | 資料安全 |
#1. 通常解法
Node.js 是一個基於 Chrome V8 引擎的 JavaScript 執行環境。 Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效。 Node.js 的包管理器 npm,是全球最大的開源庫生態系統。
Node解決了js跑在服務端的一個空缺
#2. 通用大牛級解法
加上通用解法後
可以解決高併發,它是單執行緒,當訪問量很多時,將訪問者分配到不同的記憶體中,不同的記憶體區做不同的事,以快速解決這個執行緒。就像醫院的分科室看病人。效率快,但消耗記憶體大、非同步和事件驅動。概擴起來就三點:單執行緒、非同步I/O、事件驅動。nodejs離不開ChormeV8引擎,也就是V8引擎是來解釋javascript。用nodejs來搭建高效能的Web伺服器,因此node.js是基於伺服器端的javascript
node主要應用場景是在大前端,阿里的思路是比較合適的,但是必須要注意,絕對不能讓node做太多的業務邏輯,他只適合接受人家生成好的資料,然後或渲染後,或直接傳送到客戶端。如果讓node做複雜的業務邏輯,那會得不償失的
回撥模式下的非同步是有明顯缺陷的,程式的執行順序必須依靠回撥來保證,沒有層層回撥,就沒有可以保障的邏輯順序,這也就註定了,node不能做複雜的業務邏輯。javascript語言本身也一直在和回撥做鬥爭,promise,generator都可以將回調包裝起來,在程式碼的某個部分形成形式同步,但是這種模式進化的還不完全,還不能做到與回撥完全割裂,做到完全的形式同步。但是形式同步肯定是發展的方向,這種模式即可以獲得非同步的好處,又可以有效迴避回撥帶來的程式設計困難,在業務邏輯上可以更簡單的表達。
就現在的環境來說,大家的思路還沒轉過彎,對回撥的批評認為都是不好的,這些人是不敢面對現實,javascript都在變,這些人的腦子卻不肯變,還以為回撥就代表非同步。
Node.js的發展給javascript注入了新的生命力
至於javascript的垢病,個人感覺,不在它的callback而在它的隨意性,隨意到想怎麼寫都行,但正是這點給它帶來了驚人的開發效率,做好程式碼規範和文件工作可以減少javascript的隨意性帶來的負面影響。
WEB端、移動端、桌面端、甚至嵌入式,javascript已經無處不在。接下來,ES6的實現會讓眾多習慣同步或者不喜歡回撥的開發人員能夠更快地上手javascript寫出符合他們思維習慣的程式碼,這些開發人員會是更大的群體,那麼也許javascript會橫掃應用開發也不一定。
所以,javascript很有前途,那Node.js自然就有前途。
#3. 解法對比及優缺點
大牛級解法:
優點:可以比較深入的解釋清楚node底層原理和帶來的一些良性迴圈;
缺點:如果對基礎知識不牢固,可能會帶來一系列的問題;
通用解法:
優點:可以比較概括的回答面試的問題
缺點:不夠相信,不夠全面
#4. 延伸及擴充套件問題回答參考
問題:目前前端對node的應用場景有哪些?
解答: 前端自動化,客戶端服務都在大規模的使用node進行問題的解決!
#5. 。專案中體現經驗的點
可以解決前端本地開發的服務問題,可以實現介面的代理,可以實現客戶端服務等
#6. 論壇參考
https://blog.csdn.net/hsj1669666567/article/details/79568545
https://cnodejs.org/topic/53c88a83c9507b4044b0a78a
#十八、 Vue的生命週期?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | Es6 | 非同步 | Es6非同步操作 |
#1. 通常解法
vue生命週期一共有11個,
beforeCreate,created
beforeMount,mounted
beforeUpdate, updated
actived , deactivated
beforeDestroy, destroyed
errorCaptured
#2. 通用大牛級解法
vue的生命週期主要分為幾個簡單,資料初始化,dom掛載,資料更新,元件解除安裝,在一個就是開啟了元件快取的時候,會有元件啟用和元件停用階段,每個階段都去前後兩個鉤子除了快取的那倆
資料初始化階段
beforeCreate:在例項初始化之後,資料觀測 (data observer) 和 event/watcher 事件配置之前被呼叫。
created:例項已經建立完成之後被呼叫。在這一步,例項已完成以下的配置:資料觀測 (data observer),屬性和方法的運算,watch/event 事件回撥。然而,掛載階段還沒開始,$el 屬性目前不可見。
dom掛載階段
beforeMount:在掛載開始之前被呼叫:相關的 render 函式首次被呼叫。
mounted:el 被新建立的 vm.$el 替換,並掛載到例項上去之後呼叫該鉤子。如果 root 例項掛載了一個文件內元素,當 mounted 被呼叫時 vm.$el 也在文件內。
mounted 不會承諾所有的子元件也都一起被掛載。如果你希望等到整個檢視都渲染完畢,可以用 vm.$nextTick 替換掉 mounted
資料跟新階段
beforeUpdate:資料更新時呼叫,發生在虛擬 DOM 重新渲染和打補丁之前。
updated:由於資料更改導致的虛擬 DOM 重新渲染和打補丁,在這之後會呼叫該鉤子。
當這個鉤子被呼叫時,元件 DOM 已經更新,所以你現在可以執行依賴於 DOM 的操作。然而在大多數情況下,你應該避免在此期間更改狀態。如果要相應狀態改變,通常最好使用計算屬性或 watcher 取而代之。
updated 不會承諾所有的子元件也都一起被重繪。如果你希望等到整個檢視都重繪完畢,可以用 vm.$nextTick 替換掉 updated:
快取啟用的時候會有下面兩個鉤子
activated:keep-alive 元件啟用時呼叫。
deactivated:keep-alive 元件停用時呼叫。
元件解除安裝的時候:
beforeDestroy:例項銷燬之前呼叫。在這一步,例項仍然完全可用。
destroyed:Vue 例項銷燬後呼叫。呼叫後,Vue 例項指示的所有東西都會解繫結,所有的事件監聽器會被移除,所有的子例項也會被銷燬。
#3. 解法對比及優缺點
綜上所述:第一種只是說出了生命週期方法,而第二種說出生命週期的執行作用
#4. 延伸及擴充套件問題回答參考
問題: 資料請求應該在那個生命週期,
解答:在created裡面
#5. 專案中體現經驗的點
元件中必須的內容
#6. 論壇參考
https://cn.vuejs.org/v2/api
#十九、 說一下vuex?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 5星 | Javascript | 資料儲存 | 儲存 |
#1. 通常解法
Vuex 是適用於 Vue.js 應用的狀態管理庫,為應用中的所有元件提供集中式的狀態儲存與操作,保證了所有狀態以可預測的方式進行修改;
state: state 定義了應用狀態的資料結構,同樣可以在這裡設定預設的初始狀態。
actions:Actions 即是定義提交觸發更改資訊的描述,常見的例子有從服務端獲取資料,在資料獲取完成後會呼叫store.commit()來呼叫更改 Store 中的狀態。可以在元件中使用dispatch來發出 Actions。
mutations: 呼叫 mutations 是唯一允許更新應用狀態的地方。
getters: Getters 允許元件從 Store 中獲取資料,譬如我們可以從 Store 中的 projectList 中篩選出已完成的專案列表
modules: modules 物件允許將單一的 Store 拆分為多個 Store 的同時儲存在單一的狀態樹中。隨著應用複雜度的增加,這種拆分能夠更好地組織程式碼
但是vuex也有缺點就是,vuex中儲存的資料是和網頁的生命週期同步的,當執行頁面重新整理的時候vuex中所有資料都會消失復位到初始狀態,所以不太適合做有分享頁面的資料互動(在這種專案中vuex只適合資料的集中管理,不適合資料的儲存,這種情況一般是使用路由傳遞引數會好一些),適合後臺管理系統多一些,後臺管理系統一般都是公司內部使用;
#2. 通用大牛級解法
Vuex 是專門針對vue開發的應用狀態管理庫,為應用中的所有元件提供集中式的狀態儲存與操作,保證了所有狀態以可預測的方式進行修改;
state: state 定義了應用狀態的資料結構,同樣可以在這裡設定預設的初始狀態。
actions:Actions 即是定義提交觸發更改資訊的描述,常見的例子有從服務端獲取資料,在資料獲取完成後會呼叫store.commit()來呼叫更改 Store 中的狀態。可以在元件中使用dispatch來發出 Actions。
mutations: 呼叫 mutations 是唯一允許更新應用狀態的地方。
getters: Getters 允許元件從 Store 中獲取資料,譬如我們可以從 Store 中的 projectList 中篩選出已完成的專案列表
modules: modules 物件允許將單一的 Store 拆分為多個 Store 的同時儲存在單一的狀態樹中。隨著應用複雜度的增加,這種拆分能夠更好地組織程式碼
在專案vue中主要使用vuex需要注意的是vuex相當於一個全域性的狀態,所以不要在vuex儲存大量的資料,只需要儲存全域性通用資料就可以了,還有就是當重新整理頁面的時候由於是js物件所以物件中的資料都會迴歸初始化,所以一般都需要配合本地儲存一塊使用,在就是vuex針對於vue的資料檢測做了適配,所以在vue中使用vuex做狀態管理還是比較不錯的
#3. 解法對比及優缺點
通常解法,vuex的規則解釋。通用級解法,說出了vuex的特性,優缺點,以及
。
#4. 專案中體現經驗的點
登入判斷,本地資料線上資料的同步
#5. 論壇參考
https://vuex.vuejs.org/
#二十、 小程式的元件?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
50% | 3星 | 小程式 | 功能抽象 | 元件 |
#1. 通常解法
從小程式基礎庫版本 1.6.3 開始,小程式支援簡潔的元件化程式設計。所有自定義元件相關特性都需要基礎庫版本 1.6.3 或更高。
開發者可以將頁面內的功能模組抽象成自定義元件,以便在不同的頁面中重複使用;也可以將複雜的頁面拆分成多個低耦合的模組,有助於程式碼維護。自定義元件在使用時與基礎元件非常相似。
在自定義元件的 js 檔案中,需要使用 Component() 來註冊元件,並提供元件的屬性定義、內部資料和自定義方法。
元件的屬性值和內部資料將被用於元件 wxml 的渲染,其中,屬性值是可由元件外部傳入的
元件構造器包含的屬性和方法:
properties,data,methods,behaviors(mixin),created,attached,ready,moved,detached,relations 等等
1#2. 通用大牛級解法
理解小程式元件可以對比vue元件或者react元件,頁面中多元件巢狀肯定會涉及跨元件傳值,那麼小程式的元件傳值是如何實現的。Vue或者react都屬於單向資料流的資料管理方式,小程式元件也是類似的。通過在元件上新增自定義屬性,屬性值可以是父元件的任意變數,在組建內使用properties屬性來接收。例如:
<test data="{{count}}" bindtest="func"></test>
1Component({
Properties:{
data:{
Type:String,
Value:'',
Observer:function(){}
}
}
})
這是父子元件傳值,其中type限制元件接受值的格式,value可以設定該屬性對應的預設值,observer類似於vue的watch,可以訂閱屬性值的變化,進而做相應的操作。
小程式元件由子元件向父元件傳值則用的的事件派發的方式通過triggerEvent方法觸發,並在元件標籤上bind事件監聽,執行回撥函式,來實現子父傳值。類似於vue的$emit, v-on組合
除了這些傳值方式以外,還有全域性物件掛載的方式。任何頁面都可以通過getApp()得到app例項,該app例項是小程式的全域性物件,擁有上帝視角,並且可以新增自定義屬性,利用這點也能實現跨元件傳值,不再限於父子元件之間。
#3. 解法對比及優缺點
普通解法只是小程式元件的概念和api,以及基本的使用。
大牛級解法對小程式元件的資料流進行了梳理,解釋清楚了實際操作中會遇到的具體問題,以及解決方式,體現了豐富的經驗,以及資料流概念
#4. 延伸及擴充套件問題回答參考
對比vue,react,小程式元件各自的特點,總結它們共性和不同點
#5. 專案中體現經驗的點
深刻理解小程式元件的特點和使用方法;
#6. 論壇參考
#7. https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html
#二十一、 如何理解http的快取機制?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 4星 | 面向物件 | http協議 | http快取 |
#1. 通常解法
在客戶端第一次請求資料時,此時快取資料庫中沒有對應的快取資料,需要請求伺服器,伺服器返回後,將資料儲存至快取資料庫中。
HTTP快取有多種規則,根據是否需要重新向伺服器發起請求來分類,我將其分為兩大類(強制快取,對比快取) 在詳細介紹這兩種規則之前,先通過時序圖的方式,讓大家對這兩種規則有個簡單瞭解
我們可以看到兩類快取規則的不同,強制快取如果生效,不需要再和伺服器發生互動,而對比快取不管是否生效,都需要與服務端發生互動。 兩類快取規則可以同時存在,強制快取優先順序高於對比快取,也就是說,當執行強制快取的規則時,如果快取生效,直接使用快取,不再執行對比快取規則
#2. 通用大牛級解法
從以上解法我們得知,強制快取,在快取資料未失效的情況下,可以直接使用快取資料,那麼瀏覽器是如何判斷快取資料是否失效呢?
我們知道,在沒有快取資料的時候,瀏覽器向伺服器請求資料時,伺服器會將資料和快取規則一併返回,快取規則資訊包含在響應header中。
對於強制快取來說,響應header中會有兩個欄位來標明失效規則(Expires/Cache-Control)
使用chrome的開發者工具,可以很明顯的看到對於強制快取生效時,網路請求的情況
Expires
Expires的值為服務端返回的到期時間,即下一次請求時,請求時間小於服務端返回的到期時間,直接使用快取資料。
不過Expires 是HTTP 1.0的東西,現在預設瀏覽器均預設使用HTTP 1.1,所以它的作用基本忽略。
另一個問題是,到期時間是由服務端生成的,但是客戶端時間可能跟服務端時間有誤差,這就會導致快取命中的誤差。
所以HTTP 1.1 的版本,使用Cache-Control替代。
Cache-Control
Cache-Control 是最重要的規則。常見的取值有private、public、no-cache、max-age,no-store,預設為private。
private: 客戶端可以快取
public: 客戶端和代理伺服器都可快取(前端的同學,可以認為public和private是一樣的)
max-age=xxx: 快取的內容將在 xxx 秒後失效
no-cache: 需要使用對比快取來驗證快取資料(後面介紹)
no-store: 所有內容都不會快取,強制快取,對比快取都不會觸發(對於前端開發來說,快取越多越好,so...基本上和它說886)
#3. 解法對比及優缺點
跟家強調快取的規則,對快取規則有更清楚的認識!理解各個響應頭欄位的規則。
#4. 延伸及擴充套件問題回答參考
對比快取
對比快取,顧名思義,需要進行比較判斷是否可以使用快取。
瀏覽器第一次請求資料時,伺服器會將快取標識與資料一起返回給客戶端,客戶端將二者備份至快取資料庫中。
再次請求資料時,客戶端將備份的快取標識傳送給伺服器,伺服器根據快取標識進行判斷,判斷成功後,返回304狀態碼,通知客戶端比較成功,可以使用快取資料。
#5. 專案中體現經驗的點
If-Modified-Since:
再次請求伺服器時,通過此欄位通知伺服器上次請求時,伺服器返回的資源最後修改時間。
伺服器收到請求後發現有頭If-Modified-Since 則與被請求資源的最後修改時間進行比對。
若資源的最後修改時間大於If-Modified-Since,說明資源又被改動過,則響應整片資源內容,返回狀態碼200;
若資源的最後修改時間小於或等於If-Modified-Since,說明資源無新修改,則響應HTTP 304,告知瀏覽器繼續使用所儲存的cache。
#6.論壇參考
https://blog.csdn.net/wangxiuyan0228/article/details/79457538
https://www.cnblogs.com/haorui/p/3583337.html
https://blog.csdn.net/victor_e_n_01185/article/details/72875669
#二十二、 vue-router中路由元件傳參的問題?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
70% | 4星 | 面向物件 | javaScript | Vue路由 |
#1. 通常解法
一般我們配置vue的路由的時候,在每個路由物件中是可以配置props的,配置這個屬性的目的是為了解耦路由元件;
在元件中使用 $route 會使之與其對應路由形成高度耦合,從而使元件只能在某些特定的 URl 上使用,限制了其靈活性
如下程式碼會產生耦合:
如下是通過props進行解耦
這樣的話,就可以在任何的地方重用該元件;不用擔心是在什麼環境下!
#2. 通用大牛級解法
對於vue路由物件中的配置,其實是提供了多種模式的。都是為了方便去使用對路由元件的傳參!
那麼對於props的配置有一下三種模式:
布林模式:如果props設定為true,route.params將會被設定為元件屬性;
物件模式: 如果props是一個物件,它會被按原樣設定為元件屬性。如下:
函式模式:還可以建立有一個函式來返回props,這樣就可以將引數轉換成另一種型別,將靜態的值與基於路由的值結合。
儘可能保持 props 函式為無狀態的,因為它只會在路由發生變化時起作用。如果你需要狀態來定義 props,請使用包裝元件,這樣 Vue 才可以對狀態變化做出反應。
#3. 解法對比及優缺點
-
對vue-router的理解更進一步
-
掌握多種配置方式,可以針對不同的情況
-
保持路由元件的無狀態,更利於開發
-
使$router解耦,便於重複元件的複用
#4. 延伸及擴充套件問題回答參考
實現原理:
在瀏覽器端大體有兩種實現方式:
-
通過hash字串,配合onhashchange監聽路由變化。進行檢視的切換
-
通過h5新增的pushState方法修改路由的變化。但是此種方法需要配置服務端的響應。
#5. 專案中體現經驗的點
能解耦$router和路由元件的關聯,可以在任何地方複用元件
#6.論壇參考
https://router.vuejs.org/zh/guide/essentials/passing-props.html#%E5%B8%83%E5%B0%94%E6%A8%A1%E5%BC%8F
https://www.cnblogs.com/SamWeb/p/6610733.html
https://segmentfault.com/a/1190000011123089
#二十三、 解釋一下javaScript中的繼承機制?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | Js底層原理 | javaScript | 繼承模式 |
#1. 通常解法
javascript中繼承跟java中的繼承不太一樣,一般通過call()和apply()兩種方式完成,js中的繼承是以複製的形式完成的,複製一個父物件,而不像java中直接繼承父物件,還有通過原型的方式完成繼承,也有弊端,總之js中的繼承只是形式上的對面向物件語言的一種模仿,本質上不是繼承,但用起來效果是一樣的。 至於為什麼要繼承:通常在一般的專案裡不需要,因為應用簡單,但你要用純js做一些複雜的工具或框架系統就要用到了,比如webgis、或者js框架如jquery、ext什麼的,不然一個幾千行程式碼的框架不用繼承得寫幾萬行,甚至還無法維護。
#2. 通用大牛級解法
在通用解法的基礎上,我們實現繼承的三種方式。
原型繼承
這種原型繼承的特點:既繼承了父類的模板,又繼承了父類的原型物件。優點是繼承了父類的模板,又繼承了父類的原型物件,缺點就是父類例項傳參,不是子類例項化傳參,不符合常規語言的寫法。
類繼承(借用建構函式的方式繼承)
這種原型繼承的特點:繼承了父類的模板,不繼承了父類的原型物件。優點是方便了子類例項傳參,缺點就是不繼承了父類的原型物件
因而就可以將其佔用的記憶體空間回收回來。這樣,當垃圾收集器下次再執行時,它就會釋放那些引用次數為零的值所佔用的記憶體。
混合繼承(原型繼承和類繼承)
這種原型繼承的特點:既繼承了父類的模板,又繼承了父類的原型物件。優點方便了子類例項傳參,缺點就是Boy.pertotype = new Persion() 函式又例項一次,函式內部變數又重複例項一次,大程式時候會很好效能。
#3. 解法對比及優缺點
對比以上解法,我們發現在通用解法中我們只說到JavaScript的繼承本質和為什麼要使用繼承。而在大牛級解法中我們舉出了三個常用繼承的模式並加以程式碼說明,這樣一來回答的更加具體和形象
#4. 延伸及擴充套件問題回答參考
上面是ES5的繼承機制,對應即將廣泛應用的ES6,我們也要了解它的新繼承機制
//Class之間可以通過extends關鍵字實現繼承,這比ES5的通過修改原型鏈實現繼承,要清晰和方便很多。
class ColorPoint extends Point {}
12
上面程式碼定義了一個ColorPoint類, 該類通過extends關鍵字, 繼承了Point類的所有屬性和方法。 但是由於沒有部署任何程式碼, 所以這兩個類完全一樣, 等於複製了一個Point類。 下面, 我們在ColorPoint內部加上程式碼。
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 呼叫父類的 constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 呼叫父類的 toString()
}
}
上面程式碼中, constructor方法和toString方法之中, 都出現了super關鍵字, 它在這裡表示父類的建構函式, 用來新建父類的this物件。 子類必須在constructor方法中呼叫super方法, 否則新建例項時會報錯。 這是因為子類沒有自己的this物件, 而是繼承父類的this物件, 然後對其進行加工。 如果不呼叫super方法, 子類就得不到this物件。
class Point { /* ... */ }
class ColorPoint extends Point {
constructor() {}
}
let cp = new ColorPoint(); // ReferenceError
上面程式碼中, ColorPoint繼承了父類Point, 但是它的建構函式沒有呼叫super方法, 導致新建例項時報錯。 ES5 的繼承, 實質是先創造子類的例項物件this, 然後再將父類的方法新增到this上面( Parent.apply(this))。 ES6 的繼承機制完全不同, 實質是先創造父類的例項物件this( 所以必須先呼叫super方法), 然後再用子類的建構函式修改this。 如果子類沒有定義constructor方法, 這個方法會被預設新增, 程式碼如下。 也就是說, 不管有沒有顯式定義, 任何一個子類都有constructor方法。
constructor(...args) {
super(...args);
}
另一個需要注意的地方是, 在子類的建構函式中, 只有呼叫super之後, 才可以使用this關鍵字, 否則會報錯。 這是因為子類例項的構建, 是基於對父類例項加工, 只有super方法才能返回父類例項。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // ReferenceError
super(x, y);
this.color = color; // 正確
}
}
上面程式碼中, 子類的constructor方法沒有呼叫super之前, 就使用this關鍵字, 結果報錯, 而放在super方法之後就是正確的。 下面是生成子類例項的程式碼。
let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true
上面程式碼中, 例項物件cp同時是ColorPoint和Point兩個類的例項, 這與 ES5 的行為完全一致。
#5. 專案中體現經驗的點
深刻理解JavaScript的繼承機制,利用繼承機制來優化和精簡外面的程式碼;
#6. 論壇參考
https://blog.csdn.net/caijixin/article/details/78295676
https://blog.csdn.net/qq_30100043/article/details/53542531
#二十四、 解釋一下經常使用的vue資料管理方案?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 3星 | 框架 | Vue | 資料管理 |
#1. 通常解法
vue的每個元件中都會維護一個自身資料管理屬性:data和一個父元件傳過來的資料屬性:props,我們只要合理利用data和props就可以解決大部分應用場景,比如父子元件間通訊和兄弟元件間通訊。再複雜一點的場景我們可以用到Bus和本地儲存技術,實現跨元件間的資料通訊。
#2. 通用大牛級解法
在通用解法的基礎上,介紹資料管理工具:Vuex
Vuex是一個專為 Vue.js 應用程式開發的狀態管理模式。它採用集中式儲存管理應用的所有元件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。
每一個 Vuex 應用的核心就是 store(倉庫)。“store”基本上就是一個容器,它包含著你的應用中大部分的狀態 (state)。Vuex 和單純的全域性物件有以下兩點不同:
Vuex 的狀態儲存是響應式的。當 Vue 元件從 store 中讀取狀態的時候,若 store 中的狀態發生變化,那麼相應的元件也會相應地得到高效更新。
你不能直接改變 store 中的狀態。改變 store 中的狀態的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個狀態的變化,從而讓我們能夠實現一些工具幫助我們更好地瞭解我們的應用。
現在,你可以通過 store.state 來獲取狀態物件,以及通過 store.commit 方法觸發狀態變更:
我們通過提交 mutation 的方式,而非直接改變 store.state.count,是因為我們想要更明確地追蹤到狀態的變化。這個簡單的約定能夠讓你的意圖更加明顯,這樣你在閱讀程式碼的時候能更容易地解讀應用內部的狀態改變。此外,這樣也讓我們有機會去實現一些能記錄每次狀態改變,儲存狀態快照的除錯工具。有了它,我們甚至可以實現如時間穿梭般的除錯體驗。
由於 store 中的狀態是響應式的,在元件中呼叫 store 中的狀態簡單到僅需要在計算屬性中返回即可。觸發變化也僅僅是在元件的 methods 中提交 mutation。
#3. 解法對比及優缺點
對比以上解法,我們發現在通用解法中我們只說到Vue自身的狀態管理和BUS做元件間的通訊,而在大牛級解法中我們給出了最新的類flux架構的vuex。Vuex既可以幫我們解決資料管理,並以相應的規則保證狀態以一種可預測的方式發生變化來實現元件間的通訊。這種解法讓我們在回答問題時更有層次,我們的技術深度也能夠更好的體現出來。
#4. 延伸及擴充套件問題回答參考
由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的物件。當應用變得非常複雜時,store 物件就有可能變得相當臃腫。
為了解決以上問題,Vuex 允許我們將 store 分割成模組(module)。每個模組擁有自己的 state、mutation、action、getter、甚至是巢狀子模組——從上至下進行同樣方式的分割:
#5. 專案中體現經驗的點
深刻理解vue的資料管理機制,在專案中管理好資料會幫助我們寫出更加簡潔高效的程式碼。
#6. 論壇參考
https://vuex.vuejs.org/zh/
https://vuex.vuejs.org/zh/guide/modules.html
https://segmentfault.com/a/1190000010264128
#二十五、 Js的執行原理?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | Es6 | 非同步 | Es6非同步操作 |
#1. 通常解法
js是單執行緒執行的,分為非同步任務和同步任務
#2. 通用大牛級解法
JavaScript引擎是單執行緒執行的,瀏覽器無論在什麼時候都只且只有一個執行緒在執行JavaScript程式.瀏覽器的核心是多執行緒的,它們在核心制控下相互配合以保持同步,一個瀏覽器至少實現三個常駐執行緒:javascript引擎執行緒,GUI渲染執行緒,瀏覽器事件觸發執行緒。這些非同步執行緒都會產生不同的非同步的事件.
-
javascript引擎是基於事件驅動單執行緒執行的,JS引擎一直等待著任務佇列中任務的到來,然後加以處理,瀏覽器無論什麼時候都只有一個JS執行緒在執行JS程式。
-
GUI渲染執行緒負責渲染瀏覽器介面,當介面需要重繪(Repaint)或由於某種操作引發迴流(reflow)時,該執行緒就會執行。但需要注意 GUI渲染執行緒與JS引擎是互斥的,當JS引擎執行時GUI執行緒會被掛起,GUI更新會被儲存在一個佇列中等到JS引擎空閒時立即被執行。
-
事件觸發執行緒,當一個事件被觸發時該執行緒會把事件新增到待處理佇列的隊尾,等待JS引擎的處理。這些事件可來自JavaScript引擎當前執行的程式碼塊如setTimeOut、也可來自瀏覽器核心的其他執行緒如滑鼠點選、AJAX非同步請求等,但由於JS的單執行緒關係所有這些事件都得排隊等待JS引擎處理。(當執行緒中沒有執行任何同步程式碼的前提下才會執行非同步程式碼)
當程式啟動時, 一個程序被建立,同時也執行一個執行緒, 即為主執行緒,js的執行機制為單執行緒
程式中跑兩個執行緒,一個負責程式本身的執行,作為主執行緒; 另一個負責主執行緒與其他執行緒的的通訊,被稱為“Event Loop 執行緒" 。每當遇到非同步任務,交給 EventLoop 執行緒,然後自己往後執行,等到主執行緒執行完後,再去 EventLoop 執行緒拿結果。
-
所有任務都在主執行緒上執行,形成一個執行棧(execution context stack)。
-
主執行緒之外,還存在一個"任務佇列"(task queue)。系統把非同步任務放到"任務佇列"之中,然後繼續執行後續的任務。
-
一旦"執行棧"中的所有任務執行完畢,系統就會讀取"任務佇列"。如果這個時候,非同步任務已經結束了等待狀態,就會從"任務佇列"進入執行棧,恢復執行。
-
主執行緒不斷重複上面的第三步。
"回撥函式"(callback),就是那些會被主執行緒掛起來的程式碼。非同步任務必須指定回撥函式,當非同步任務從"任務佇列"回到執行棧,回撥函式就會執行。"任務佇列"是一個先進先出的資料結構,排在前面的事件,優先返回主執行緒。主執行緒的讀取過程基本上是自動的,只要執行棧一清空,"任務佇列"上第一位的事件就自動返回主執行緒。
主執行緒從"任務佇列"中讀取事件,這個過程是迴圈不斷的,所以整個的這種執行機制又稱為Event Loop。
從主執行緒的角度看,一個非同步過程包括下面兩個要素:
發起函式(或叫註冊函式)A
回撥函式callbackFn
它們都是在主執行緒上呼叫的,其中註冊函式用來發起非同步過程,回撥函式用來處理結果。
非同步程序有:
類似onclick等,由瀏覽器核心的DOM binding模組處理,事件觸發時,回撥函式新增到任務佇列中;
setTimeout等,由瀏覽器核心的Timer模組處理,時間到達時,回撥函式新增到任務佇列中;
Ajax,由瀏覽器核心的Network模組處理,網路請求返回後,新增到任務佇列中。
例如setTimeout(fn, 1000),其中的setTimeout就是非同步過程的發起函式,fn是回撥函式。用一句話概括:工作執行緒將訊息放到訊息佇列,主執行緒通過事件迴圈過程去取訊息。
訊息佇列:訊息佇列是一個先進先出的佇列,它裡面存放著各種訊息。
事件迴圈:事件迴圈是指主執行緒重複從訊息佇列中取訊息、執行的過程。
流程如下:
-
主執行緒讀取js程式碼, 形成相應的堆和執行棧, 執行同步任務
-
當主執行緒遇到非同步任務,,指定給非同步程序處理, 同時繼續執行同步任務
-
當非同步程序處理完畢後, 將相應的非同步任務推入到任務佇列首部
-
主執行緒任務處理完畢後,,查詢任務佇列,則取出一個任務佇列推入到主執行緒的執行棧
重複執行第2、3、4步,這就稱為事件迴圈
#3. 解法對比及優缺點
綜上所述:第一種只是關鍵字,而第二種說出其中的正真的執行原理
#4. 專案中體現經驗的點
程式的執行順序
#二十六、 說一下前端安全?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 5星 | Javascript | 資料儲存 | 儲存 |
#1. 通常解法
惡意攻擊者往Web頁面裡注入惡意Script程式碼,使用者瀏覽這些網頁時,就會執行其中的惡意程式碼,可對使用者進行盜取cookie資訊、會話劫持等各種攻擊.;
#2. 通用大牛級解法
#1.XSS(Cross Site Scripting,跨站指令碼攻擊)
這是前端最常見的攻擊方式,很多大型網站(如 Facebook)都被 XSS 攻擊過。
舉一個例子,我在一個部落格網站正常發表一篇文章,輸入漢字、英文和圖片,完全沒有問題。但是如果我寫的是惡意的 JS 指令碼,例如獲取到document.cookie然後傳輸到自己的伺服器上,那我這篇部落格的每一次瀏覽都會執行這個指令碼,都會把訪客 cookie 中的資訊偷偷傳遞到我的伺服器上來。
其實原理上就是黑客通過某種方式(釋出文章、釋出評論等)將一段特定的 JS 程式碼隱蔽地輸入進去。然後別人再看這篇文章或者評論時,之前注入的這段 JS 程式碼就執行了。JS 程式碼一旦執行,那可就不受控制了,因為它跟網頁原有的 JS 有同樣的許可權,例如可以獲取 server 端資料、可以獲取 cookie 等。於是,攻擊就這樣發生了。
XSS的危害
XSS 的危害相當大,如果頁面可以隨意執行別人不安全的 JS 程式碼,輕則會讓頁面錯亂、功能缺失,重則會造成使用者的資訊洩露。
比如早些年社交網站經常爆出 XSS 蠕蟲,通過釋出的文章內插入 JS,使用者訪問了感染不安全 JS 注入的文章,會自動重新發布新的文章,這樣的文章會通過推薦系統進入到每個使用者的文章列表面前,很快就會造成大規模的感染。
還有利用獲取 cookie 的方式,將 cookie 傳入入侵者的伺服器上,入侵者就可以模擬 cookie 登入網站,對使用者的資訊進行篡改。
XSS的預防
那麼如何預防 XSS 攻擊呢?—— 最根本的方式,就是對使用者輸入的內容進行驗證和替換,需要替換的字元有:
& 替換為:&
< 替換為:<
> 替換為:>
” 替換為:"
‘ 替換為:'
/ 替換為:/
替換了這些字元之後,黑客輸入的攻擊程式碼就會失效,XSS 攻擊將不會輕易發生。
除此之外,還可以通過對 cookie 進行較強的控制,比如對敏感的 cookie 增加http-only限制,讓 JS 獲取不到 cookie 的內容。
#2. CSRF(Cross-site request forgery,跨站請求偽造)
CSRF 是借用了當前操作者的許可權來偷偷地完成某個操作,而不是拿到使用者的資訊。
例如,一個支付類網站,給他人轉賬的介面是http://buy.com/pay?touid=999&money=100,而這個介面在使用時沒有任何密碼或者 token 的驗證,只要開啟訪問就直接給他人轉賬。一個使用者已經登入了http://buy.com,在選擇商品時,突然收到一封郵件,而這封郵件正文有這麼一行程式碼
<img src="http://buy.com/pay?touid=999&money=100"/>
1他訪問了郵件之後,其實就已經完成了購買。
CSRF 的發生其實是藉助了一個 cookie 的特性。我們知道,登入了http://buy.com/之
後, cookie 就會有登入過的標記了,此時請求http://buy.com/pay?touid=999&money=100
是會帶著 cookie 的,因此 server 端就知道已經登入了。而如果在http://buy.com/
去請求其他域名的 API 例如http://abc.com/api
時,是不會帶 cookie 的,這是瀏覽器的同源策略的限制。但是 —— 此時在其他域名的頁面中,請求http://buy.com/pay?touid=999&money=100
,會帶著http://buy.com/
的cookie
,這是發生 CSRF 攻擊的理論基礎。
預防 CSRF 就是加入各個層級的許可權驗證,例如現在的購物網站,只要涉及現金交易,肯定要輸入密碼或者指紋才行。除此之外,敏感的介面使用POST請求而不是GET也是很重要的。
#3.解法對比及優缺點
通常解法,前端常見的安全問題。通用級解法,說出瞭如何模擬攻擊,如何防禦攻擊。
#4.專案中體現經驗的點
登入許可權控制,富文字內容釋出
#二十七、 Promise物件的理解?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
50% | 3星 | 小程式 | 功能抽象 | 元件 |
#1. 通常解法
Promise 是非同步程式設計的一種解決方案,比傳統的解決方案——回撥函式和事件——更合理和更強大。它由社群最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了Promise物件。
所謂Promise,簡單說就是一個容器,裡面儲存著某個未來才會結束的事件(通常是一個非同步操作)的結果。從語法上說,Promise 是一個物件,從它可以獲取非同步操作的訊息。Promise 提供統一的 API,各種非同步操作都可以用同樣的方法進行處理。
基本用法:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 非同步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
提供的方法
Promise.prototype.then()
Promise.prototype.catch()
Promise.prototype.finally()
Promise.all()
Promise.race()
#2. 通用大牛級解法
Promise物件的特點:
a. 物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。
b. 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise物件的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。
有了Promise物件,就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。此外,Promise物件提供統一的介面,使得控制非同步操作更加容易。
Promise也有一些缺點。首先,無法取消Promise,一旦新建它就會立即執行,無法中途取消。其次,如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部。第三,當處於pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
如果某些事件不斷地反覆發生,一般來說,使用 Stream 模式是比部署Promise更好的選擇。
除了promise也可以考慮es6的generator和async函式
#3. 解法對比及優缺點
普通解法只是promise物件的概念,以及基本的使用。
大牛級解法對promise的特點進行了解釋,也總結了promise的缺點,並提供了更多的選項,體現了經驗。
#4. 延伸及擴充套件問題回答參考
JavaScript的非同步程式設計總結;
Ajax的非同步原理是什麼
#5. 專案中體現經驗的點
深刻理解promise的特點和使用方法;
#6. 論壇參考
https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/events.html
#二十八、 解釋一下移動端多倍屏1px畫素問題
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 3星 | 佈局 | 頁面佈局 | 多倍屏適配 |
#1. 通常解法
#先介紹下多倍屏:
多倍屏是指1個邏輯畫素對應多個物理畫素。在2倍屏下,1個邏輯畫素就對應2個物理畫素;
在3倍屏下,1個邏輯畫素就對應3個物理畫素。
正如我們的標準設計稿尺寸是750*1334(也就是iphone6、7、8能夠顯示的畫素),
雖然我們的iphone6、7、8的螢幕尺寸是375*667,
但螢幕是2倍屏,所以可以顯示的實際畫素是750*1334。
常見的2倍屏是iphone6、7、8,常見的3倍屏是iphone6plus、7plus、8plus。
#1px畫素問題:
1px畫素問題來了,在多倍屏下邏輯上的1畫素顯示的多個物理畫素。那麼解決方案也就來了。如在兩倍屏下,1個CSS畫素對應2個物理畫素, 那麼我們只需要想辦法把border的寬度變為0.5px, 那麼展現就是1個物理畫素了,也就能解決1px畫素問題了。
效果預覽:
線性漸變:
#2. 通用大牛級解法
使用偽元素繪製border + 根據多倍屏進行縮放 和 設定border寬度為小數(僅ios支援)
#3. 解法對比及優缺點
不同型別的優缺點 | 背景漸變 | border的寬度為小數 | 偽元素+縮放 |
---|---|---|---|
優點 | 使用簡單,可以設定多條邊 | 簡單方便 | 可以適配任意多倍屏 |
缺點 | 只能解決兩倍屏 | Ios支援,android不支援 | 程式碼稍微繁瑣 |
#4. 延伸及擴充套件問題回答參考
還有多種其他解決1px畫素的方案,常見的如:viewport縮放+rem佈局,border-image,box-shadow等,這些方案都會有些自己的侷限性,可以參考下面的連結做進一步研究
#5. 專案中體現經驗的點
為了更好的還原設計稿,我們需要相容各種多倍屏,這樣可以使我們的頁面看起來更加美觀、優雅
#6. 論壇參考
https://www.jianshu.com/p/7e63f5a32636
http://www.runoob.com/css3/css3-gradients.html
https://blog.csdn.net/caochenyu0/article/details/53813074
#二十九、 解釋一下經常使用的資料型別檢測:
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
90% | 3星 | 框架 | 型別檢測 | 檢測資料型別 |
#1. 通常解法
使用typeof檢測資料型別,首先返回的都是一個字串,其次字串中包含了對應的資料型別,例如:"number"、"string"、"boolean"、"undefined"、"function"、"object"
#2. 通用大牛級解法
在通用解法的基礎上,介紹資料型別檢測
①instanceof
只要在當前例項的原型鏈上,用instanceof檢測出來的結果都是true,所以在類的原型繼承中,最後檢測出來的結果未必是正確的
②constructor
constructor即建構函式,作用和instanceof非常的相似。
constructor可以處理基本資料型別的檢測
constructor檢測Object和instanceof不一樣,一般情況下是檢測不了的 constructor的侷限性:我們可以把類的原型進行重寫,在重寫的過程中,很有可能把之前的constructor給覆蓋了,這樣檢測出來的結果就是不準確的。對於特殊的資料型別null和undefined,它們的所屬型別是Null和Undefined,但是瀏覽器把這兩個類保護起來了,不允許在外面訪問使用
③Object.prototype.toStrong.call()
Object.prototype.toStrong.call()是檢測資料型別最準確最常用的方式,起原理為:
先獲取Object原型上的toString方法,讓方法執行,並且改變方法中的this關鍵字的指向;
Object.prototype.toString 它的作用是返回當前方法的執行主體(方法中this)所屬類的詳細資訊
#3. 解法對比及優缺點
不同型別的優缺點 | typeof | instanceof | constructor | Object.prototype.toString.call |
---|---|---|---|---|
優點 | 使用簡單 | 能檢測出引用型別 | 基本能檢測所有的型別(null和undefined) | 檢測出所有的型別 |
缺點 | 只能檢測出基本型別(除null) | 不能檢測出基本型別且不能跨iframe | constructor易被修改,也不能跨iframe | IE6下,undefined和null均為Object |
#4. 延伸及擴充套件問題回答參考
檢測原型繼承的情況:
#5. 專案中體現經驗的點
深刻理解資料的基本型別檢測,在專案中當我們不確定函式中的型別是,我們可以利用資料型別來檢測函式中的型別,從而方便我們更好的完成任務
#6. 論壇參考
https://www.talkingcoder.com/article/6333557442705696719
https://www.jianshu.com/p/75057391ad51
https://blog.csdn.net/lhjuejiang/article/details/79623973
#三十、 什麼是MVVM?
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | mvvm | Mvvm | 什麼是MVVM? |
#1. 通常解法
MVVM 是 Model-View-ViewModel 的縮寫。mvvm 是一種設計思想。
#通用大牛級解法
#定義
MVVM 是 Model-View-ViewModel 的縮寫。mvvm 是一種設計思想。Model 層代表資料模型,也可以在 Model 中定義資料修改和操作的業務邏輯;View 代表 UI 元件,它負責將資料模型轉化成 UI 展現出來,ViewModel 是一個同步 View 和 Model 的物件。
在 MVVM 架構下,View 和 Model 之間並沒有直接的聯絡,而是通過 ViewModel 進行互動,Model 和 ViewModel 之間的互動是雙向的, 因此 View 資料的變化會同步到 Model 中,而 Model 資料的變化也會立即反應到 View 上。
ViewModel 通過雙向資料繫結把 View 層和 Model 層連線了起來,而 View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需關注業務邏輯,不需要手動操作 DOM, 不需要關注資料狀態的同步問題,複雜的資料狀態維護完全由 MVVM 來統一管理。
mvc 和 mvvm 其實區別並不大。都是一種設計思想。主要就是 mvc 中 Controller 演變成 mvvm 中的 viewModel。mvvm 主要解決了 mvc 中大量的 DOM 操作使頁面渲染效能降低,載入速度變慢,影響使用者體驗。和當 Model 頻繁發生變化,開發者需要主動更新到 View 。
#Mvvm:
Model:資料模型
View:帶特殊屬性的 html 模板
ViewModel:依靠 Directive,修改資料 & 自動渲染
#MVVM的實現主要是三個核心點:
響應式:vue如何監聽data的屬性變化
模板解析:vue的模板是如何被解析的
渲染:vue模板是如何被渲染成HTML的
#2. 解法對比及優缺點
綜上所述:第一種只是關鍵字,而第二種說出其中的正真的執行原理
#3. 專案中體現經驗的點
對vue中mvvm的掌握程度
#
#三十一、 Vue的響應原理:
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | Vue | vue | Vue的響應原理 |
#1. 通常解法
Vue的資料響應主要是依賴了Object.defineProperty(),響應式系統依賴於三個重要的類:Dep 類、Watcher 類、Observer 類。Dep 類作為釋出者的角色,Watcher 類作為訂閱者的角色,Observer 類則是連線釋出者和訂閱者的紐帶,決定訂閱和釋出的時機。在 Observer 類中,為 data 的每個屬性都例項化一個 Dep 類,即釋出者。並且在取值時讓訂閱者訂閱,在賦值時釋出者釋出通知,讓訂閱者做出各自的響應。Watcher 類在建構函式中執行了一個方法,將自己賦值,並且執行了取值操作,這樣就成功的完成了訂閱操作。一旦資料發生變化,即有了賦值操作,釋出者就會發送通知,訂閱者就會執行自己的 update 方法來響應這次資料變化
#2. 通用大牛級解法
Vue 最獨特的特性之一,是其非侵入性的響應式系統。資料模型僅僅是普通的 JavaScript 物件。而當你修改它們時,檢視會進行更新。這使得狀態管理非常簡單直接,不過理解其工作原理同樣重要,這樣你可以迴避一些常見的問題。
當你把一個普通的 JavaScript 物件傳給 Vue 例項的 data 選項,Vue 將遍歷此物件所有的屬性,並使用Object.defineProperty把這些屬性全部轉為getter/setter。Object.defineProperty 是 ES5 中一個無法 shim 的特性,這也就是為什麼 Vue 不支援 IE8 以及更低版本瀏覽器。
這些 getter/setter 對使用者來說是不可見的,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。這裡需要注意的問題是瀏覽器控制檯在列印資料物件時 getter/setter 的格式化並不同,所以你可能需要安裝vue-devtools來獲取更加友好的檢查介面。每個元件例項都有相應的 watcher 例項物件,它會在元件渲染的過程中把屬性記錄為依賴,之後當依賴項的 setter 被呼叫時,會通知 watcher 重新計算,從而致使它關聯的元件得以更新。
受現代 JavaScript 的限制 (而且 Object.observe 也已經被廢棄),Vue 不能檢測到物件屬性的新增或刪除。由於 Vue 會在初始化例項時對屬性執行 getter/setter 轉化過程,所以屬性必須在 data 物件上存在才能讓 Vue 轉換它,這樣才能讓它是響應的。
由於 Vue 不允許動態新增根級響應式屬性,所以你必須在初始化例項前宣告根級響應式屬性,哪怕只是一個空值,如果你未在 data 選項中宣告 message,Vue 將警告你渲染函式正在試圖訪問的屬性不存在。這樣的限制在背後是有其技術原因的,它消除了在依賴項跟蹤系統中的一類邊界情況,也使 Vue 例項在型別檢查系統的幫助下執行的更高效。而且在程式碼可維護性方面也有一點重要的考慮:data 物件就像元件狀態的概要,提前宣告所有的響應式屬性,可以讓元件程式碼在以後重新閱讀或其他開發人員閱讀時更易於被理解。
可能你還沒有注意到,Vue 非同步執行 DOM 更新。只要觀察到資料變化,Vue 將開啟一個佇列,並緩衝在同一事件迴圈中發生的所有資料改變。如果同一個 watcher 被多次觸發,只會被推入到佇列中一次。這種在緩衝時去除重複資料對於避免不必要的計算和 DOM 操作上非常重要。然後,在下一個的事件迴圈“tick”中,Vue 重新整理佇列並執行實際 (已去重的) 工作。Vue 在內部嘗試對非同步佇列使用原生的 Promise.then 和 MessageChannel,如果執行環境不支援,會採用 setTimeout(fn, 0) 代替。
例如,當你設定 vm.someData = 'new value' ,該元件不會立即重新渲染。當重新整理佇列時,元件會在事件迴圈佇列清空時的下一個“tick”更新。多數情況我們不需要關心這個過程,但是如果你想在 DOM 狀態更新後做點什麼,這就可能會有些棘手。雖然 Vue.js 通常鼓勵開發人員沿著“資料驅動”的方式思考,避免直接接觸 DOM,但是有時我們確實要這麼做。為了在資料變化之後等待 Vue 完成更新 DOM ,可以在資料變化之後立即使用 Vue.nextTick(callback) 。這樣回撥函式在 DOM 更新完成後就會呼叫。
#3. 解法對比及優缺點
綜上所述:第一種只是關鍵字,而第二種說出其中的正真的執行原理
#4. 專案中體現經驗的點
事件的構建機制原理,以及如何執行
#三十二、 高階元件原理:
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | React | 高階元件 | 高階元件 |
#1. 通常解法
接收函式作為輸入,或者輸出另一個函式的一類函式,被稱作高階函式
#2. 通用大牛級解法
高階元件通過包裹(wrapped)被傳入的React元件,經過一系列處理,最終返回一個相對增強(enhanced)的React元件,供其他元件呼叫。
高階元件是react應用中很重要的一部分,最大的特點就是重用元件邏輯。它並不是由
React API定義出來的功能,而是由React的組合特性衍生出來的一種設計模式。
2.高階元件可以看做是裝飾器模式(Decorator Pattern)在React的實現。即允許向一個現有的物件新增新的功能,同時又不改變其結構,屬於包裝模式(Wrapper Pattern)的一種
3.ES7中添加了一個decorator的屬性,使用@符表示,可以更精簡的書寫
#兩種形式:
A、屬性代理
引入裡我們寫的最簡單的形式,就是屬性代理(Props Proxy)的形式。
a. 操作props 最直觀的就是接受到props,我們可以做任何讀取,編輯,刪除的很多自定義操作。包括hoc中定義的自定義事件,都可以通過props再傳下去
b. refs獲取元件例項 當我們包裝Usual的時候,想獲取到它的例項怎麼辦,可以通過引用(ref),在Usual元件掛載的時候,會執行ref的回撥函式,在hoc中取到元件的例項。
c. 抽離state
這裡不是通過ref獲取state, 而是通過 { props, 回撥函式 } 傳遞給wrappedComponent元件,通過回撥函式獲取state。這裡用的比較多的就是react處理表單的時候。通常react在處理表單的時候,一般使用的是受控元件(文件),即把input都做成受控的,改變value的時候,用onChange事件同步到state中。當然這種操作通過Container元件也可以做到,具體的區別放到後面去比較
B、反向繼承
反向繼承(Inheritance Inversion),簡稱II,跟屬性代理的方式不同的是,II採用通過 去繼承WrappedComponent,本來是一種巢狀的關係,結果II返回的元件卻繼承了WrappedComponent,這看起來是一種反轉的關係。 通過繼承WrappedComponent,除了一些靜態方法,包括生命週期,state,各種function,我們都可以得到
#應用場景
通常我會通過高階元件去優化之前老專案寫的不好的地方,比如兩個頁面UI幾乎一樣,功能幾乎相同,僅僅幾個操作不太一樣,卻寫了兩個耦合很多的頁面級元件。當我去維護它的時候,由於它的耦合性過多,經常會新增一個功能(這兩個元件都要新增),我要去改完第一個的時候,還要改第二個。而且有時候由於我的記性不好,會忘掉第二個... 就會出現bug再返工。更重要的是由於個人比較懶,不想去重構這部分的程式碼,因為東西太多了,花費太多時間。所以加新功能的時候,我會寫一個高階元件,往HOC裡新增方法,把那兩個元件包裝一下,也就是屬性代理。這樣新程式碼就不會再出現耦合,舊的邏輯並不會改變,說不定哪天心情好就會抽離一部分功能到HOC裡,直到理想的狀態。
另一種情況就是之前寫過一個元件A,做完上線,之後產品加了一個新需求,很奇怪要做的元件B跟A幾乎一模一樣,但稍微有區別。那我可能就通過II的方式去繼承之前的元件A,比如它在didMount去fetch請求,需要的資料是一樣的。不同的地方我就會放到HOC裡,儲存新的state這樣,再通過劫持渲染,把不同的地方,新增的地方進行處理。但其實這算Hack的一種方式,能快速解決問題,也反映了元件設計規劃之初有所不足(原因比較多)。
Container解決不了的時候甚至不太優雅的時候。其實大部分時候包一層Container元件也能做到差不多的效果,比如操作props,渲染劫持。但其實還是有很大區別的。比如我們現在有兩個功能的container,新增樣式和新增處理函式的,對Usual進行包裝
注意點(約束)
· 最重要的原則就是,注意高階元件不會修改子元件,也不拷貝子元件的行為。高階元件只是通過組合的方式將子元件包裝在容器元件中,是一個無副作用的純函式
· 要給hoc新增class名,便於debugger。我上面的好多栗子元件都沒寫class 名,請不要學我,因為我實在想不出叫什麼名了... 當我們在chrome裡應用React-Developer-Tools的時候,元件結構可以一目瞭然,所以DisplayName最好還是加上。
· 靜態方法要複製 無論PP還是II的方式,WrappedComponent的靜態方法都不會複製,如果要用需要我們單獨複製。
· refs不會傳遞。 意思就是HOC裡指定的ref,並不會傳遞到子元件,如果你要使用最好寫回調函式通過props傳下去。
· 不要在render方法內部使用高階元件。簡單來說react的差分演算法會去比較 NowElement === OldElement, 來決定要不要替換這個elementTree。也就是如果你每次返回的結果都不是一個引用,react以為發生了變化,去更替這個元件會導致之前元件的狀態丟失。
#3. 解法對比及優缺點
綜上所述:第一種只是關鍵字,而第二種說出其中的真正的原理
#4. 專案中體現經驗的點
高階元件的解耦和靈活性
#5. 論壇參考
#三十三、 React與Vue的區別與聯絡原理:
面試概率 | 級別 | 應用模組或方向 | 解決問題 | 考核點 |
---|---|---|---|---|
95% | 3星 | React與vue | 區別與聯絡 | React與Vue的區別與聯絡 |
#1. 通常解法
Vue是用於構建使用者介面的漸進式框架,React是構建使用者介面的元件化開發
#2. 通用大牛級解法
在渲染使用者介面的時候,DOM的操作是最昂貴,不幸的是沒有庫可以讓這些原始操作變得更快。我們能做的最好的就是:儘量減少DOM操作。Vue 和 React 都使用虛擬DOM來實現,並且兩者工作一樣好;
相同點:
-
.都支援伺服器端渲染
-
都使用虛擬DOM來實現
-
都有Virtual DOM,元件化開發,通過props引數進行父子元件資料的傳遞,都實現webComponent規範
-
只有框架的骨架,其他的功能如路由、狀態管理等是框架分離的元件。
-
都是JavaScript的UI框架,資料驅動檢視,專注於創造前端的富應用
-
都有支援native的方案,React的React native,Vue的weex
-
都有管理狀態,React有redux,Vue有自己的Vuex(自適應vue,量身定做)
在 React 中,所有的元件的渲染功能使用的都是JSX。JSX 是使用 XMl 語法編寫 Javascript 的一種語法糖,它可以使用的完整的程式語言JavaScript來構建檢視頁面,工具對JSX的支援相比於現有可用的其他Vue模板還是比較先進的,在 Vue 中我們採用的 Web 技術並在其上面擴充套件,使用Template在寫模板的過程中,樣式風格已確定和更少地涉及業務邏輯,一個模板總是被宣告的,模板中任何 HTMl 都是有效的,相比之下,React功能沒有 Vue 模板系統的豐富。需要從元件檔案中分離出HTML程式碼。
在效能方面,當我們考慮重新渲染功能。當元件的狀態發生變化時,React的機制會觸發整個元件樹的重新呈現,並且由於 React 有大量的檢查機制,能讓它提供許多有用的警告和錯誤提示資訊,但可能需要使用額外的屬性來避免不必要地重新渲染子元件。雖然Vue的重新渲染功能是開箱即用的,但Vue提供了優化的重新渲染,其中系統在渲染過程中跟蹤依賴關係並相應地工作。
在React中應用中的狀態是(React)關鍵的概念。也有一些配套框架被設計為管理一個大的state物件,如Redux。此外,state物件在React應用中是不可變的,意味著它不能被直接改變(這也許不一定正確)。在React中你需要使用setState()方法去更新狀態;在Vue中,state物件並不是必須的,資料由data屬性在Vue物件中進行管理,而在Vue中,則不需要使用如setState()之類的方法去改變它的狀態,在Vue物件中,data引數就是應用中資料的儲存者。
不同點:
-
React嚴格上只針對MVC的view層,Vue則是MVVM模式
-
virtual DOM不一樣,vue會跟蹤每一個元件的依賴關係,不需要重新渲染整個元件樹.
-
而對於React而言,每當應用的狀態被改變時,全部元件都會重新渲染,所以react中會需要shouldComponentUpdate這個生命週期函式方法來進行控制
-
元件寫法不一樣, React推薦的做法是 JSX + inline style, 也就是把HTML和CSS全都寫進JavaScript了,即'all in js';
-
Vue推薦的做法是webpack+vue-loader的單檔案元件格式,即html,css,jd寫在同一個檔案;
-
資料繫結: vue實現了資料的雙向繫結,react資料流動是單向的
-
state物件在react應用中不可變的,需要使用setState方法更新狀態;
-
在vue中,state物件不是必須的,資料由data屬性在vue物件中管理
#3. 解法對比及優缺點
在以下場景中,Vue比反應更好:
最新文件和更簡單的語法。更小,更快,更靈活。豐富的HTML模板,易於開發。
React比Vue.js好:
需要構建移動應用程式。專業和出色的社群支援,以解決任何問題。需要構建大型應用程式。輕量級,易於版本遷移
#4. 專案中體現經驗的點
Reat與Vue只有框架的骨架,其他的功能如路由、狀態管理等是框架分離的元件。
論壇參考