這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 為了保證的可讀性,本文采用意譯而非直譯。 在 JS 面試中,經常會看到一些簡單而又沙雕的題目,這些題目包含一些陷阱,但這些在我們規範的編碼下或者業務中基本不會出現。 有些面試官就是這樣,不專註於制定代碼的標準和規範上,卻用不規範的代碼去檢 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
為了保證的可讀性,本文采用意譯而非直譯。
在 JS 面試中,經常會看到一些簡單而又沙雕的題目,這些題目包含一些陷阱,但這些在我們規範的編碼下或者業務中基本不會出現。 有些面試官就是這樣,不專註於制定代碼的標準和規範上,卻用不規範的代碼去檢驗別人是否細心。
這魔幻的世界就是一個攀比優越感的,我能考你,我就是比你優越,真實。
來看看這 7 個沙雕題目是哪些。
1. 偶然創建的全局變數
面試官問
在下麵的代碼中 typeof a
和 typeof b
結果各自是什麼?(沙雕)
function foo() { let a = b = 0; a++; return a; } foo(); typeof a; // => ??? typeof b; // => ???
答案
這個代碼的重點在第二行
:let a = b = 0
。這個語句聲明瞭一個局部變數 a
,但是它也聲明瞭一個全局變數b
。
在 foo()
作用域或全局作用域中都沒有聲明變數 b
。因此 JS 引薦將b = 0
表達式解釋為 window.b = 0
。
如下圖所示,函數 foo
中的 i
都是一個偶然創建的全局變數:
同樣,在咱們的問題中,b
是一個偶然創建的全局變數。在瀏覽器中,上面的代碼相當於如下:
function foo() { let a; window.b = 0; a = window.b; a++; return a; } foo(); typeof a; // => 'undefined' typeof window.b; // => 'number'
typeof a
是 'undefined'
。變數 a
僅在 foo()
作用域中聲明,在外部作用域內不可用。
typeof b
結果是 'number'
。b
是一個值為 0
的全局變數
2. 數組的 length 屬性
面試官問
clothes[0]
的值是什麼?(沙雕)
const clothes = ['jacket', 't-shirt']; clothes.length = 0; clothes[0]; // => ???
答案
數組對象的 length
屬性具有一些特殊的行為:
減少
length
屬性的值的副作用是刪除自己的
數組元素,這些元素的數組索引位於新舊長度值之間。
由於 length
屬性行為,當 JS 執行 clothes.length = 0
時,刪除所有的 clothes
項。 所以 clothes[0]
的值為 undefined
,因為 clothes
數組已被清空。
3.考驗眼力的魔幻題
面試官問
下麵代碼中 numbers 數組的內容是什麼? 註意 for()
後加了一個分號(;
),真是沙雕。
const length = 4; const numbers = []; for (var i = 0; i < length; i++);{ numbers.push(i + 1); } numbers; // => ???
答案
上面代碼中 for()
後加了一個分號(;
) ,加上分號,JS 會認為該語句結束,所以 for 迴圈執行了4次空語句,當退出迴圈的時候,此時的 i 值為 4。
然後執行 { numbers.push(i + 1); }
,所以最終 numbers
內容只有一個數字 5
。
上面的代碼相當於下麵的代碼
const length = 4; const numbers = []; var i; for (i = 0; i < length; i++) { // does nothing } { // a simple block numbers.push(i + 1); } numbers; // => [5]
用不規範的代碼去檢驗別人是否細心,我覺得很沙雕。
4.自動分號插入
面試官問
arrayFromValue()
返回什麼值?(沙雕)
function arrayFromValue(items) { return [items]; } arrayFromValue(10); // => ???
答案
這裡需要註意的 return
和 [items]
之間已經換行了,JS 會在換行之間自動插入分號。所以上面等價下麵的代碼:
function arrayFromValue(items) { return; [items]; } arrayFromValue(10); // => undefined
return;
在函數內部使該函數返回 undefined
,所以 arrayFromValue(10)
的值為 undefined
。
5. 被考爛的一個經典閉包問題
面試官問
下麵的代碼執行結果是什麼?(能不能換個題)
let i; for (i = 0; i < 3; i++) { const log = () => { console.log(i); } setTimeout(log, 100); }
答案
當你對 JS 基礎不是很瞭解的時候,很容易給出 0, 1, 2
的答案,我第一次在學校遇到這個題目也是這個答案。
執行這段代碼的過程有兩個階段。
階段1
-
for()
迭代3
次。在每次迭代時,都會創建一個新函數log()
,該函數將捕獲變數i
。然後,setTimout()
調度log()
的執行。 -
當
for()
迴圈完成時,變數i
的值為3
。
log()
是一個捕獲變數 i
的閉包,該變數在 for()
迴圈的外部作用域中定義。重要的是要瞭解閉包在詞法上捕獲了變數 i
。
階段 2
第二階段發生在 100
毫秒之後
setTimeout()調用 3
個 log()
回調。log()
讀取變數 i
的當前值,即 3
。
這就是為什麼控制台輸出為 3
, 3
和 3
的原因
6. 浮點運算
面試官問
下麵的代碼輸出是什麼? (能不能換個題)
0.1 + 0.2 === 0.3 // => ???
答案
首先,來看一下 0.1 + 0.2
的值
0.1 + 0.2; // => 0.30000000000000004
0.1
和 0.2
的和不等於 0.3
,但略高於 0.3
。
由於以二進位方式對浮點數進行編碼,因此像浮點數相加之類的操作會產生舍入誤差。
因此, 0.1 + 0.2 === 0.3
是 false
。
7. 變數的提升
面試官問
如果在聲明之前訪問 myVar
和 myConst
會發生什麼?(能不能換個題)
myVar; // => ??? myConst; // => ??? var myVar = 'value'; const myConst = 3.14;
答案
提升和時間死區是影響 JS 變數生命周期的兩個重要概念。
在聲明之前訪問 myVar
的結果是 undefined
,因為使用 var 聲明的變數會被提升且值為 undefined
。
但是,在聲明行之前訪問 myConst
會引發 ReferenceError
。在代碼行 const myConst = 3.14
之前,const
變數處於臨時死區。