談談前端面試中遇到的問題(一)
- 2019 年 10 月 21 日
- 筆記
前言
歇了一個多月,終於是拿了駕照,也算是完成了人生計劃中的其中一個,沒有過去2019年。
2019年的全部計劃估計是完不成了,想要完成多少,還是要看接下來的努力。
歇息了一個月,最近剛剛開始面試,前兩個面試是一點準備都沒有,去面試也僅僅是考慮一下自己現在的情況,有目的的去準備面試。
一個多月,感覺忘記了很多,在此記下面試中遇到的問題,以來自勉。
題目
1、React context是如何工作的?
更多的時候,我們在組件層級間進行數據傳遞,都會用到props,但是如果需要傳遞的子屬性太多,我的組件屬性就有可能會寫得很長。而這時候,context或許是個解決方案。
context作用是為了避免在組件間層層傳遞變數。我們可以通過createContext(null)來創建一個新的context,新創建的context包含一個Provider以及一個Consumer。
如果我們想要在組件間層層傳遞變數,則需要用Provider來包裹父組件,在Provider包裹下的層層組件,都可以通過Consumer包裹子組件來讀取傳遞的變數。
2、react兄弟組件間通訊方式
第一種笨方法,子組件1傳遞給父組件,接著傳遞給子組件2.
第二種利用事件的發布訂閱。
第三種大家都知道,用redux管理數據。原理和第一種+第二種差不多,不過是更規範的數據管理和數據流傳遞和事件發布訂閱方式。
3、setState原理
先說明,setState既可以同步也可以非同步。比如在setTimeout的包裹中setState會立即執行。我們正常方式下的setState是非同步狀態,因為React中的狀態合併,使得多次操作,在最終的一次時間點做數據更新,避免每次都執行DOM操作耗費性能。
那麼setState的原理大致可以描述為:設置新的state會將這個新的state存儲在一個狀態隊列,如果達到批量更新的節點,則進行狀態合併,更新成組件最終的state或者props。
而setState就是將新的狀態放置在狀態隊列中的操作函數,由此也可以知道,如果直接更改state,如this.state = 1這樣的操作,並不會直接更新狀態隊列的,所以這個操作是無效的。
這個只是簡單的回答,如果要從源碼上回答,還得知道setState的事務機制。
4、PureComponent和Component的區別
PureComponent會幫助我們在shouldComponentUpdate生命周期中進行一次淺比較。
淺比較只檢查值類型的值和引用類型的引用是否相等,如果要做比較深入的判斷,還是應該在shouldComponentUpdate生命周期自行判斷。
5、如何避免重複渲染。
這個問題,其實也相當於是React性能問題的一個。
首先,不要在render中為函數綁定參數,每次參數更改都會創建新的函數,則會刷新組件或者子組件。
其次,盡量不要使用派生數據綁定到組件屬性,每次傳遞props都會生成新的數據,即使數據一樣,也會導致重複渲染。
還有,組件設定的key值要和里和固定,這樣當數據一致和key一致的時候,組件也不會重新渲染。
最終,你還可以修改shouldComponentUpdate生命周期返回值來手動達到不重複渲染的目的。
6、getDerivedStateFromProps幹了什麼?
getDerivedStateFromProps是React16.3中新增的一個靜態的生命周期函數,未來即將移除的神明周期有三個: `,componentWillMountcomponentWillReceiveProps ,componentWillUpdate
這個生命周期是映射props到state上,相當於是執行setState操作。所以,每次父組件發生props變化,都會執行setState操作。這也可能導致重複渲染,感覺盡量也減少使用吧。
getDerivedStateFromProps 是一個靜態方法, 是一個和組件自身”不相關”的角色. 在這個靜態方法中, 除了兩個默認的位置參數 nextProps 和 currentState 以外, 你無法訪問任何組件上的數據.
7、解析HTTP 304 狀態碼
數據請求的時候,如果伺服器發現客戶端有快取,並且時間沒過期,則返回304狀態。
請求頭中的Last Modified和f Modified Since來進行比較判斷是否需要返回304,或者更新數據返回200.
8、什麼是高階組件?
我們知道函數的參數是函數,返回的是新的函數,則稱為高階函數。
高階組件是返回組件的組件,也就是傳遞參數是組件,對這個組件進行加工成為一個新的組件並返回。
他用來幹什麼?一般用來屬性代理,也就是把原本的props和新的props組合成一個新的組件的屬性。所以,我們如果要創建一個loading效果組件,或者是成功失敗等狀態組件,可以用高階組件來實現。
9、for…of能遍歷什麼?
可迭代對象。如Arrays(數組), Strings(字元串), Maps(映射), Sets(集合)等。
10、如何避免遍歷到原型上的屬性?
第一、for..in + hasOwnProperty方法
第二、Object.keys()
11、事件循環。
JavaScript是單執行緒執行模型,執行的時候將會區分為主執行緒和任務隊列。主執行緒執行完畢,會從任務隊列中讀取新的任務放入主執行緒進行執行,這個讀取過程是循環讀取,所以也叫事件循環。
任務隊列分為宏任務和微任務,同層次,先執行微任務,再執行宏任務。
微任務:promise.then()、process.nextTick()
宏任務:setTimeOut()、setInterval()
12、瀏覽器的渲染流程
這個問題應該就是輸入url到頁面呈現問題的變種,只不過此時的側重點是獲取完數據之後進行的渲染流程。
根據李兵老師的瀏覽器工作原理一節做如下回答:
第一步,HTML轉換成DOM
第二步,CSS轉換成瀏覽器可理解的styleSheets,然後計算DOM節點的樣式
第三步,創建布居樹,計算元素的布局資訊
第四步,對布居樹進行分層,構建分層樹
第五步,為每個圖層生產繪製列表,並將其提交到合成執行緒
第六步,合成執行緒將圖層轉化為圖塊,進而將圖塊轉化成點陣圖
第七步,合成執行緒發送繪製命令給瀏覽器
第八步,瀏覽器根據繪製命令生成頁面,並顯示到顯示器上。
13、deffer和async的區別
瀏覽器腳本,在普通的情況下,是會依次執行。但是我們可以用deffer和async關鍵字來讓腳本非同步執行。
但是,deffer是按照載入順序執行DOMContentLoaded之前執行,但是async則是腳本載入完畢之後立即執行(不考慮依賴以及DOM的載入狀態),一般來說,deffer要比async好一點。
14、DOM選擇器中,querySelectorAll和getElementByClass的區別?
querySelectorAll 返回的是一個 Static Node List,而 getElementsBy 系列的返回的是一個 Live Node List。
所以靜態節點列表相當於是快照,不影響文檔操作,所以我們可以遍歷循環querySelectorAll生產的數據。
但是動態節點列表,如果我們的一些查詢和操作就會變成死循環。
從性能上來講,getElementByClass要更快。
15、map和forEach的區別
forEach返回undefined,map會返回新的數組。
forEach沒辦法中止循環,但是map可以通過返回false或者出錯來中止。
16、call、apply以及bind的區別。
三者都是改變this執行,不同的是,call和apply是直接生成了函數調用,而bind則是返回了一個函數,你需要再次執行才會達到相同的效果。
call和apply又是因為參數的傳遞方式不一樣,apply傳遞的是數組,call傳遞的單個參數的陳列。
bind則是以函數調用參數的方式傳遞參數。
17、css中的box-sizing
懵逼了,不知道是啥,之前根本沒用過。
查了下,box-sizing 屬性允許你以某種方式定義某些元素,以適應指定區域。例如,假如您需要並排放置兩個帶邊框的框,可通過將 box-sizing 設置為 “border-box”。這可令瀏覽器呈現出帶有指定寬度和高度的框,並把邊框和內邊距放入框中。
box-sizing的值有三個,content-box:只有內容、border-box:包括邊框、inherit:繼承自父元素。
總結
剛開始面試,有些生疏,並且有時候明明記得,卻死活想不起來,大概是太長時間沒有思考技術的原因。事後仔細思考,覺得這些問題都是很基礎,很簡單的題目,只要好好準備一下,應該還是慢慢會好起來的。
我的部落格:http://www.gaoyunjiao.fun/?p=163