一次前端面試的提問總結

後排的風過發表於2019-03-02

記一次比較遙遠的面試提問,記得多少寫多少,附較詳細的解答,歡迎指出錯誤。

1. 說說CSS中的相對定位與絕對定位:

  • position: relative;為相對定位,根據自身位置來進行定位。
  • position: absolute;為絕對定位,若父級節點的position屬性不為static,則根據父級節點位置進行定位;否則則繼續尋找上一級position屬性不為static的節點進行定位,若都沒有找到,則以視窗進行定位。

2. this的指向

  1. 一般情況下,this指向呼叫該函式的物件
  2. 箭頭函式裡的this指向定義時所在的物件
  3. this的指向可以通過bind函式改變

3. 類裡靜態方法的this指向

this指向呼叫該函式的物件,而靜態方法不用建立例項來呼叫,而是通過類本身來直接呼叫,故this指向這個類本身而不是例項。

4. letconst

  • let:
  1. 定義的變數只在當前程式碼塊有效,存在區域性作用域。
  2. 不存在變數提升,即未定義前訪問變數會報錯,而不是返回undefined
  3. 在同一個程式碼塊內不允許重複定義同一個變數。
  • const
  1. 擁有let的所有特性
  2. const定義的常量指向的地址不能改變。
  3. 如果定義的是個物件或者陣列這種引用型別,只是不能改變它指向的記憶體地址,但它的屬性可以改變。

5. 在React元件的render函式裡呼叫setState會發生什麼問題?哪個生命週期函式可以阻止這個問題發生?PureCompoent。

會發生死迴圈問題,因為setState又會觸發render函式。shouldComponentUpdate生命週期函式返回false的時候不會觸發render,可以阻止這個問題發生。

PureCompoent在shouldComponentUpdate實現一個淺比較,需要注意的是以下程式碼不會觸發render

const newState = this.state.someState;

newState.attr = `newValue`;
this.setState({
    someState: newState,
});
複製程式碼

這是因為淺比較是比較這個變數的地址,地址不變則返回false
下面程式碼會觸發render

const newState = this.state.someState;

newState.attr = `newValue`;
this.setState({
    someState: {...newState},
});
複製程式碼

還可以使用immutable來寫,這裡使用的是immutable的一個輔助庫immutability-helper-x:

import update from `immutability-helper-x`;
...

this.setState({
    someState: update.$set(this.state.someState, `attr`, `newValue`),
});

複製程式碼

6. 淺拷貝和深拷貝。

淺拷貝

淺拷貝就是把物件的屬性的值都複製一份到新的記憶體地址,但只複製一層,若屬性的值為物件,則還是原來的引用。如:

const obj = {
    child: {
        key: `value`,
    },
};
const newObj = shallowCopy(obj);

console.log(newObj.child === obj.child);  // true
複製程式碼

實現方法:

function shallowCopy(obj) {
    // ES6
    // return {...obj};
    
    return Object.assign({}, obj);
}
複製程式碼

深拷貝

而深拷貝則遍歷整個物件,把這個物件所有的值都移到新的記憶體空間,不存在原來的引用,如:

const obj = {
    child: {
        key: `value`,
    },
};
const newObj = deepCopy(obj);

console.log(newObj.child === obj.child);  // false
複製程式碼

深拷貝可以通過遍歷整個物件來拷貝,也有一種比較簡單的實現方法,但效率都比較差。

function deepCopy(obj) { 
  return JSON.parse(JSON.stringify(obj)); 
}
複製程式碼

7. Node中的事件迴圈

因為JS是單執行緒的,執行I/O操作時會阻塞執行緒,如果一直等待I/O操作完成再執行下面的程式碼是不現實的,因此就需要事件迴圈。

事件迴圈就是當遇到像I/O這種阻塞執行緒的操作時,把他們交給系統核心去進行處理,Node繼續往下執行程式碼,等到I/O操作執行完後告知Node,然後Node會把響應的回撥函式加進事件佇列等待執行。

8. 瀏覽器快取

強快取

HTTP狀態碼為200(from cache),它的優點是沒有訪問伺服器,直接在本地讀取快取,減少HTTP請求,但也因為如此,這也是它的缺點,因為它不知道伺服器資源是否有更新,從而無法獲取到最新的資源,這個問題通常用給靜態資源新增Hash值來判斷資源有無更新,若Hash值不同,則會請求獲取最新資源。

相關Header有(按優先順序排序):

  1. Cache-Control。設定一個最大有效期,如Cache-Control: max-age=36000000
  2. Expires。它描述一個最後的過期時間,如Expires: Tue, 17 Jul 2018 15:42:01 GMT

協商快取

HTTP狀態碼為304,當沒有強快取或者強快取過期時,會傳送請求到伺服器,若伺服器發現資源沒有更新,則返回304告訴客戶端不必更新。因為它還是要傳送請求,所以比強快取慢。

相關Header有:

  1. Last-ModifiedIf-Modified-Since
  2. ETagIf-None-Match

9. 記憶體洩漏

JS提供自動管理記憶體,稱為“垃圾回收機制”,通常用的是“引用計數”,即當一個物件的引用數為0時就把它釋放回收。而當一個不在使用的物件的引用數又不為0的時候,無法把他進行回收,即造成記憶體洩漏問題。

相關文章