好程式設計師Java教程分享JavaScript常見面試題四

好程式設計師IT發表於2019-10-28

  好程式設計師Java 教程分享JavaScript常見面試題四1、 下面的程式碼將輸出什麼到控制檯,為什麼?

 

console.log(1 + "2" + "2");console.log(1 + +"2" + "2");console.log(1 + -"1" + "2");console.log(+"1" + "1" + "2");console.log( "A" - "B" + "2");console.log( "A" - "B" + 2);

 

上面的程式碼將輸出以下內容到控制檯:

 

"122""32""02""112""NaN2"NaN

 

原因是

 

這裡的根本問題是,JavaScript(ECMAScript) 是一種弱型別語言,它可對值進行自動型別轉換,以適應正在執行的操作。讓我們透過上面的例子來說明這是如何做到的。

 

1 1 + "2" + "2"  輸出: "122"  說明:  1 + "2"  是執行的第一個操作。由於其中一個運算物件 ("2") 是字串, JavaScript 會假設它需要執行字串連線,因此,會將  的型別轉換為  "1" ,  1 + "2" 結果就是  "12" 。然後,  "12" + "2"  就是  "122"

 

2 :  1 + +"2" + "2"  輸出:  "32"  說明:根據運算的順序,要執行的第一個運算是  +"2"( 第一個  "2"  前面的額外  被視為一元運算子 ) 。因此, JavaScript 將  "2"  的型別轉換為數字,然後應用一元  ( 即,將其視為一個正數 ) 。其結果是,接下來的運算就是  1 + 2  ,這當然是  3 。然後我們需要在一個數字和一個字串之間進行運算 ( 即,  和  "2") ,同樣的, JavaScript 會將數值型別轉換為字串,並執行字串的連線,產生  "32"

 

3 :  1 + -"1" + "2"  輸出:  "02"  說明:這裡的解釋和前一個例子相同,除了此處的一元運算子是  而不是  + 。先是  "1"  變為  1 ,然後當應用  時又變為了  -1  ,然後將其與  1 相加,結果為  0 ,再將其轉換為字串,連線最後的  "2"  運算物件,得到  "02"

 

4 :  +"1" + "1" + "2"  輸出:  "112"  說明:雖然第一個運算物件  "1" 因為字首的一元  運算子型別轉換為數值,但又立即轉換回字串,當連線到第二個運算物件  "1"  的時候,然後又和最後的運算物件 "2"  連線,產生了字串  "112"

 

5 :  "A" - "B" + "2"  輸出:  "NaN2"  說明:由於運算子  不能被應用於字串,並且  "A"  和  "B"  都不能轉換成數值,因此, "A" - "B" 的結果是  NaN ,然後再和字串  "2"  連線,得到  "NaN2" 

 

6 :  "A" - "B" + 2  輸出:  NaN  說明:參見前一個例子,  "A" - "B"  結果為  NaN 。但是,應用任何運算子到 NaN 與其他任何的數字運算物件,結果仍然是  NaN

 

2 下面的遞迴程式碼在陣列列表偏大的情況下會導致堆疊溢位。在保留遞迴模式的基礎上,你怎麼解決這個問題?

 

var list = readHugeList();var nextListItem = function() { var item = list.pop(); if (item) { // process the list item...

 

nextListItem();

 

}

 

};

 

潛在的堆疊溢位可以透過修改nextListItem  函式避免:

 

var list = readHugeList();var nextListItem = function() { var item = list.pop(); if (item) { // process the list item...

 

setTimeout( nextListItem, 0);

 

}

 

};

 

堆疊溢位之所以會被消除,是因為事件迴圈操縱了遞迴,而不是呼叫堆疊。當 nextListItem  執行時,如果  item 不為空, timeout 函式 (nextListItem) 就會被推到事件佇列,該函式退出,因此就清空呼叫堆疊。當事件佇列執行其 timeout 事件,且進行到下一個  item  時,定時器被設定為再次呼叫  extListItem 。因此,該方法從頭到尾都沒有直接的遞迴呼叫,所以無論迭代次數的多少,呼叫堆疊保持清空的狀態。

 

3 JavaScript 中的“閉包”是什麼 ? 請舉一個例子。

 

閉包是一個可以訪問外部( 封閉 ) 函式作用域鏈中的變數的內部函式。閉包可以訪問三種範圍中的變數:這三個範圍具體為: (1) 自己範圍內的變數, (2) 封閉函式範圍內的變數,以及 (3) 全域性變數。

 

下面是一個簡單的例子:

 

var globalVar = "xyz";

 

(function outerFunc(outerArg) { var outerVar = 'a';

 

(function innerFunc(innerArg) { var innerVar = 'b'; console.log( "outerArg = " + outerArg + "\n" + "innerArg = " + innerArg + "\n" + "outerVar = " + outerVar + "\n" + "innerVar = " + innerVar + "\n" + "globalVar = " + globalVar);

 

})(456);

 

})(123);

 

在上面的例子中,來自於 innerFunc ,  outerFunc 和全域性名稱空間的變數都在  innerFunc 的範圍內。因此,上面的程式碼將輸出如下:

 

outerArg = 123innerArg = 456outerVar = ainnerVar = bglobalVar = xyz

 

4 下面的程式碼將輸出什麼:

 

for (var i = 0; i < 5; i++) {

 

setTimeout(function() { console.log(i); }, i * 1000 );

 

}

 

解釋你的答案。閉包在這裡能起什麼作用?

 

上面的程式碼不會按預期顯示值0 1 2 3 ,和 4 ,而是會顯示 5 5 5 5 ,和 5

 

原因是,在迴圈中執行的每個函式將整個迴圈完成之後被執行,因此,將會引用儲存在 i 中的最後一個值,那就是 5

 

閉包可以透過為每次迭代建立一個唯一的範圍,儲存範圍內變數的每個唯一的值,來防止這個問題,如下:

 

for (var i = 0; i < 5; i++) {

 

(function(x) {

 

setTimeout(function() { console.log(x); }, x * 1000 );

 

})(i);

 

}

 

這就會按預期輸出0 1 2 3 ,和 4 到控制檯。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2661635/,如需轉載,請註明出處,否則將追究法律責任。

相關文章