我的前端面試日記(一)
阿新 • • 發佈:2019-01-23
第一次寫面試經歷,雖然之前有過一些電話面試經歷,但相對而言感覺此次的經歷對自己收穫還是比較大,這裡留下面經當作日記吧!(面試時間:2018-6-12 下午2:10;時長:50min;公司:*)
1、說說React,為什麼選擇React
(一)、React特點
高效、虛擬DOM,最大限度地減少與DOM的互動:
- 瀏覽器在渲染網頁時,會先將HTML文件解析並構建DOM樹,然後與CSSOM樹生成RenderObject樹,最後渲染成頁面。瀏覽器中渲染引擎和JavaScript引擎是分離的,渲染引擎會提供一些介面給JavaScript呼叫,它們二者通訊是通過橋接的,效能其實是很差的。
- 以往,為了優化效能通常採用的辦法是減少DOM操作次數。而React提出了一個新的思路就是虛擬DOM:元件的HTML結構不再是直接生成DOM,而是對映生成虛擬的JavaScript DOM結構,React通過diff演算法將最小變更寫入DOM中,從而減少DOM的實際次數,提升效能。
伺服器端渲染
- React提供開箱即用的伺服器端渲染,伺服器端渲染解除了伺服器端對瀏覽器的依賴,它會將“可視”部分先渲染,然後再交給客戶端做渲染。
元件化編碼
- React 的一切都是基於元件的。可以通過定義一個元件,然後在其他的元件中,可以像HTML標籤一樣引用它。說得通俗點,元件其實就是自定義的標籤;通過 React 構建元件,使得程式碼更加容易得到複用,能夠很好的應用在大專案的開發中。
宣告式設計
- React採用聲明範式,函數語言程式設計,可以輕鬆描述應用。
靈活
- React可以與已知的庫或框架很好地配合。
JSX
- JSX 是 JavaScript 語法的擴充套件。React開發不一定使用 JSX ,但我們建議使用它。
單向響應的資料流
- React 實現了單向響應的資料流,資料是自頂向下單向流動的,即從父元件到子元件,這種原則讓元件之間的關係變得簡單可預測;props作為外部介面、state作為內部狀態。
(二)、為什麼選擇React
- 相比其他如Vue、angular的雙向資料繫結的框架,個人比較喜歡這種比較流程化的單向資料流形式,因為可以更好的預測資料的變化;
- 當然最主要的原因是學校圖書館,對於React的書籍資料更豐富(。。。。道出了真相、尷尬)
2、剛剛你說到了虛擬DOM的Diff演算法,談談你對它的理解
- 因為當時沒有怎麼看這個演算法,所以只是憑藉之前的知識點簡單的說了下;
- 這裡在具體的回顧下:
- React的Diff演算法巧妙的使用了試探法將複雜度為O(n^3)的數差異比較演算法轉換成O(n)複雜度的問題;
該演算法基於兩個假定:
- 相同類的兩個元件將會生成相似的樹形結構,而不同類的兩個元件將會生成不同的樹形結構;
- 可以為元素提供唯一的標識,確保該元素在不同的渲染過程中保持不變。
具體實現細節:
- (樹形結構的比較)即首先檢查兩個節點的差異
節點型別不同時
- React會把它們當做兩個不同的字樹,導致直接移除之前的那顆子樹,然後建立並插入之前的那顆子樹
- 優點:巧妙的避開了對樹形結構的大量差異檢測,然後關注與相同的部分,實現了快速而又精確的差異檢測邏輯;
- 缺陷:如果兩個子樹具有相似的結構,即頂節點不同,子節點結構相同,這時本來只需要對不同的頂節點進行刪除插入操作,但是React會將整個子樹都刪除然後從新構建插入
3、對React生命週期瞭解嗎
(1)、裝載過程
當元件第一次被渲染時,依次呼叫的函式:
- construction
- getInitalState
- getDefaultProps
- componentWillMount
- render
- componentDidMount
(2)、更新過程
更新過程會依次呼叫以下生命週期函式,其中render函式和“裝載”過程一樣:
- componentWillReceiveProps
- shouldComponentUpdate- componentWillUpdate
- render
- componentDidUpdate
- 並不是所有的更新過程都會執行全部函式。
(3)、React元件的解除安裝過程只涉及一個函式componentWillUnmount
4、說到shouldComponentUpdate,你是如何使用的、如何判斷是否更新
- 在生命週期中render函式決定了該渲染什麼,而shouldComponentUpdate決定了一個元件什麼時候不需要渲染;
- shouldComponentUpdate(nextProps,nextState)接收兩個引數,即此次渲染的props和state物件,返回一個布林,預設返回true,表示進行更新;返回false表示此次更新不需要到此終止;
- 通過比較此次props、state和上次是否相同決定是否需要進行更新可以很好的避免不必要的更新操作,提升效能;
- 因為props和state的是物件,平時使用的一般都淺層比較,如果需要對兩個物件進行深度全面比較,我考慮的是使用JSON.stringify()
5、如果在React中我需要獲取DOM節點、應該在什麼階段獲取、如何獲取
- 要獲取DOM節點的話,需要在componentDidMount或者componentDidUpdata中獲取,因為只有在這個階段真實DOM節點才構建完成了
- 獲取DOM節點可以使用ref屬性
6、如果我又需要通過原生js獲取這個節點的父節點呢
- 可能只是作為一個過渡,比較簡單、直接回答了使用DOM節點的parentNode屬性獲取;不過這裡還是補充一點。
nextSibling 屬性 :
- 返回目標節點的下一個兄弟節點。
- 如果目標節點後面沒有同屬於一個父節點的節點,nextSibling 將返回null ;
- nextSibling 屬性是一個只讀屬性。
previousSibling屬性 :
- 返回目標節點的前一個兄弟節點。
- 如果目標節點前面沒有同屬於一個父節點的節點,previousSibling 將返回null ;
- previousSibling 屬性是一個只讀屬性。
parentNode 屬性 :
- 注:parentNode屬性返回的節點永遠是一個元素節點,因為只有元素節點才有可能有子節點。
- 當然有個例外:
- document節點,他沒有父節點。所以document節點的parentNode屬性將返回null;
- parentNode 屬性是一個只讀屬性。
7、現在我又需要以類名獲取DOM
- 當時直接說的是:可以使用document.getElementsByClassName()、document.querySelector()、document.querySelectorAll();
- 然後又引出了區別問題~
8、說說以上三種方法的區別
回答:
- getElementsByClassName()、和querySelectorAll()返回的是一個DOM列表,雖然可以用迴圈遍歷,但是它們只是偽陣列,不能使用陣列的方法;
- getElementsByClassName()只能通過類名獲取,而和querySelectorAll、querySelector是使用CSS選擇器獲取的,
- 當時只說了querySelector是返回一個DOM節點,有點錯誤吧;querySelector是返回文件中匹配指定的CSS選擇器的第一元素
9、剛剛你說到偽陣列,那麼如何區分一個物件是陣列呢
- 回答:
obj instanceof Array
如果返回true或者false;Object.prototype.toString.call(obj) === "[object Array]"
;
- 還有一個當時沒有說道:
obj.constructor == Array
為true或false
- 當時還補充了一個ES6的
Array.isArray(obj)
,用於確定傳遞的值是否是一個 Array,如果物件是 Array,則為true; 否則為false。
10、談到ES6,說說你對ES6的瞭解
- 回答:
- ES6主要增加了一些新的特效,如:
- const定義常量,但是const定義的常量只是值不可變,即基本資料型別不可變,對於引用型別,因為它建立的是引用,所以即使使用const定義的物件,其屬性還是可變的;
- let定義變數,相對於var,它修復了一些問題,比如變數提升、重複定義等問題,並且const和let的定義具有塊級作用域;
- 對於字串擴充套件有:字串模板、還有一些方法(忘了,趕緊跳過);
- 還有就是:剩餘引數、函式預設引數、模組化、Promise、裝飾器、Symbol、set和map等;
- 剛學習不久,大概就說了這些;最近也在更新ES6的筆記深入理解ES6
對ES6並沒有深入的問,直接從let和const的塊級作用域引到了閉包
11、剛剛說到塊級作用域,談談它和閉包的區別,就是說一般什麼時候使用閉包?
回答:
- 閉包使用的作用的話主要是為了獲取函式內部的變數和將變數儲存下來,使其不被垃圾回收器回收,供給之後使用;
- 使用的話一般是為了封裝作用域,即代替全域性變數,避免全域性變數汙染;
- 因為使用閉包,會將變數儲存不被回收器回收,所以應該儘量避免使用,防止造成記憶體洩漏
- 答的不是太全面,這裡補充:
閉包的應用場景
- 使用閉包代替全域性變數
- 函式外或在其他函式中訪問某一函式內部的引數
- 在函式執行之前為要執行的函式提供具體引數
- 在函式執行之前為函式提供只有在函式執行或引用時才能知道的具體引數
- 為節點迴圈繫結click事件,在事件函式中使用當次迴圈的值或節點,而不是最後一次迴圈的值或節點
- 暫停執行
- 包裝相關功能
12、說到回收器,說說如何判斷一個變數可回收,如果我需要使用閉包,該如何避免你所說的記憶體洩漏?
- 感覺有點給自己挖坑了,(回收機制、記憶體洩漏不是太懂啊
~~) 回答:
- 一個變數的可回收性,一般需要根據瀏覽器js引擎的回收器機制判斷,大概有兩種方式(當時只說到了一種);
- 即引用計數:引用計數的含義是跟蹤記錄每個變數被引用的次數,當期的引用次數為0時表回收
- 一般手動清除是將它賦值為null
科普:
引用計數:
- 當宣告一個變數並將一個引用型別值賦給該變數時,則這個值的引用次數便是1,如果同一個值又被賦給另一個變數,則該值的引用次數加1,相反,如果包含對這個值引用的變數又取得了另一個值,則這個值的引用次數減1。當這個值的引用次數為0時,說明沒有辦法訪問到它了,因而可以將其佔用的記憶體空間回收
標記清除:
- 當變數進入環境時,例如,在函式中宣告一個變數,就將這個變數標記為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變數所佔用的記憶體,因為只要執行流進入相應的環境,就可能會用到它們。而當變數離開環境時,則將其標記為“離開環境”。
13、HTML5瞭解嗎?談一談
- HTML5 主要增加了一些語義化標籤和一些API、刪除了一些元素
- 繪畫 canvas
- 用於媒介回放的 video 和 audio 元素
- 本地離線儲存 localStorage 長期儲存資料,瀏覽器關閉後資料不丟失
- sessionStorage 的資料在瀏覽器關閉後自動刪除
- 語意化更好的內容元素,比如 article、footer、header、nav、section
- 表單控制元件,calendar、date、time、email、url、search
- 新的技術webworker, websocket, Geolocation
- 移除的元素:
- 純表現的元素:basefont,big,center,font, s,strike,tt,u
- 對可用性產生負面影響的元素:frame,frameset,noframes
沒有到這麼詳細,以上回顧
14、說到localStorage和sessionStorage還有cookie談談他們的區別?
- 相同點:都可以作為瀏覽器儲存,且都不能進行跨域訪問;
不同點:
- cookie始終會在同源 http 請求頭中攜帶(即使不需要),在瀏覽器和伺服器間來回傳遞
- sessionStorage 和 localStorage 不會自動把資料發給伺服器,僅在本地儲存;
- sessionStorage 和 localStorage 儲存大小比cookie大得多,可以達到5M或更大;
- localStorage 儲存持久資料,瀏覽器關閉後資料不丟失除非主動刪除資料;
- sessionStorage 資料在當前瀏覽器視窗關閉後自動刪除;
- cookie 設定的cookie過期時間之前一直有效,與瀏覽器是否關閉無關。
15、簡歷上看你上過《計算機網路》?談一談ISO七層,按順序說說
應用層、表示層、會話層、傳輸層、網路層、資料鏈路層、物理層
16、說說http和ftp協議分別在哪一層
- 都處於應用層(現在回顧好像錯了一個~~~~)
科普:
- 應用層:允許訪問OSI環境的手段(應用協議資料單元APDU)(HTTP、FTP、SMTP、DNS)
- 表示層:對資料進行翻譯、加密和壓縮(表示協議資料單元PPDU)
- 會話層:建立、管理和終止會話(會話協議資料單元SPDU);
- 傳輸層:提供端到端的可靠報文傳遞和錯誤恢復(段Segment)(TCP和UDP);
- 網路層:負責資料包從源到宿的傳遞和網際互連(包PackeT)IP定址;
- 資料鏈路層:將位元組裝成幀和點到點的傳遞(幀Frame)
- 物理層:通過媒介傳輸位元,確定機械及電氣規範(位元Bit)
17、說說你對http的瞭解,就說狀態碼吧,你常用的狀態碼及其含義
- HTTP超文字傳輸協議,基於請求/響應模式。
- HTTP是無狀態協議,FTP是有狀態
狀態碼:
- 100:post請求第一次傳送頭資訊後伺服器返回100,表示請求繼續;
- 200: 表示請求正常,請求成功;
- 301:永久重定向;
- 302: 臨時重定向;
- 304: 用於協商快取,表示瀏覽器快取資源未改變,任然可用
- 400:請求語法或引數錯誤;
- 401:認證未通過,如跨域未通過;
- 403:請求未授權;
- 404:找不到相應資源的位置;
- 500:伺服器內部出錯;
- 502: 錯誤閘道器
18、聽你談到瀏覽器快取,說說你所知道的快取方式
- 快取型別有兩種,強快取和協商快取
- 強快取:不會向伺服器傳送請求,直接從快取中讀取資源(Etag、cache-control);
- 協商快取:向伺服器傳送請求,伺服器會根據這個請求的request header的一些引數來判斷是否命中協商快取,如果命中,則返回304狀態碼並帶上新的response header通知瀏覽器從快取中讀取資源;
科普更多瀏覽器快取細節:深入瀏覽器快取
19、那接下來我們談談CSS,兩個div垂直佈局,上面的設定margin—bottom:50px;下面的margin-top:100px;此時兩個div相距多少
- 100px,因為垂直方向的margin會存在重疊現象
20、如果我需要消除這種情況,如何處理
- 父元素設定overflow:hidden形成BFC、或者子元素設定border;
科普更多
- 外層元素padding代替
- 內層元素透明邊框 border:1px solid transparent;
- 內層元素絕對定位 postion:absolute:
- 外層元素 overflow:hidden;
- 內層元素 加float:left;或display:inline-block;
- 內層元素padding:1px;
21、現在我需要實現兩個div水平佈局
- 使用flex佈局:父元素設定display;flex
- 使用float佈局(或者display:inline-block)
//html
<div class="box">
<div class="item1">float</div>
<div class="item2">overflow:hidden</div>
</div>
//CSS
.item1 {
float: left;
//display:inline-block
}
.item2 {
overflow: hidden;
//display:inline-block
}
22、現在我改變需求,左邊固定寬度,右邊自適應
- 左邊定寬width:200px;設定浮動float:left;右邊overflow:hidden(或者margin-left:左邊寬度);
- 父元素display:flex;左邊定寬width:200px;;右邊設定項伸展屬性flex-grow: 1;
- 父元素position:relative;左邊定寬width:200px;position:absolute;右邊margin-left:左邊寬度;
- 父元素display:table;左邊定寬width:200px;display:tabel-cell;右邊width:100%。
23、現在我需要,兩個div進行兩列布局,要求高度不定(父元素也是),我需要兩個div實時等高,即左邊div高度被其內子元素撐高時,右邊的div高度和左邊同步
- 父元素display:table;左邊定寬width:200px;display:tabel-cell;右邊width:100%。
- 父元素display:flex;align-items:stretch;左邊定寬width:200px;;右邊設定項伸展屬性flex-grow: 1;
24、突然又有新的需求,實現左右兩邊固定寬度,中間自適應
- 使用flex佈局:父元素display:flex;左邊定寬width:200px;右邊定寬width:200px;中間flex-grow:1;
使用浮動佈局:父元素overflow:hidden;左邊定寬width:200px;float:left;右邊定寬width:200px;float:right;中間margin:0 200px;
- 這裡有個坑,那就是HTML結構必須得變換,即中和右要調換位置(當時沒想到,一直被問你確定就這樣可以?短路短路~)
- 細想因為center的div在正常文件流中,且佔據全屏寬度,自然之後的浮動元素會被放置下一行
// Html結構
<div class="box">
<div class="left">left</div>
<div class="right">right</div>
<div class="center">center</div>
</div>
// CSS樣式佈局
.left {
width: 200px;
background: bisque;
float: left;
}
.center{
background: red;
margin: 0 200px;
}
.right {
background: rgba(22,220,22,0.5);
float: right;
width: 200px;
}
使用絕對定位佈局:
絕對定位法原理是將左右兩邊使用absolute定位,因為絕對定位使其脫離文件流,後面的center會自然流動到他們上面,然後使用margin屬性,留出左右元素的寬度,既可以使中間元素自適應螢幕寬度。(這種方式)
// CSS樣式佈局 .left { width: 200px; background: bisque; position: absolute; } .center{ background: red; margin: 0 200px; } .right { background: rgba(22,220,22,0.5); position: absolute; right: 0; width: 200px; }
// html結構
<div class="box">
<div class="wrap">
<div class="center">center</div>
</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
// CSS 樣式
.left {
width: 200px;
background: bisque;
float: left;
margin-left: -100%;
}
.wrap {
float: left;
width: 100%;
}
.center{
background: red;
margin: 0 200px;
}
.right {
background: rgba(22,220,22,0.5);
float: left;
margin-left: -200px;
width: 200px;
}
整個過程歷時1個小時左右,感覺還好吧,怎麼說不管過沒過,起碼知道自己還有哪些方面不足,可以針對性的深入學習。
- 最後附上此次面試涉及的一些知識點