javascript 是古怪的。不信??試着用
map
和
parseInt
将一個字元串數組轉成數字數組。将下面的段代碼輸入到控制台(在Chrome浏覽器按 F12),并回車。
['1', '7', '11'].map(parseInt);
複制
我們得到結果是
[1, NaN, 3]
,而不是我們想要的
[1, 7, 11]
。為何?為了探究其原因,我們先探讨一些javascript觀點。如果你是個’太長不看’,可以直接到總結部分。

true 或者 false
看下面這個
if-else
的簡單條件語句。
if (true) {
// 總是執行
} else {
// 絕對不會執行
}
複制
在這個例子中,
if-else
的語句總是
true
,是以
if
下的塊語句總是執行,而
else
語句塊絕不會執行。這很好了解,因為
true
是
boolean
。如果不是
boolean
作為條件的話會是怎麼樣呢?
if ("hello world") {
// 執行這個?
console.log("Condition is true");
} else {
// 還是這個?
console.log("Condition is false");
}
複制
當你在控制台裡執行後,會發現
if
下的語句塊被執行,說明
string
對象
"hello world"
轉成
boolean
值為
true
。所有的javascript的值要麼是
true
要麼是
false
。當在一個
boolean
環境下時,如
if-else
,都會被轉成
true
或
false
。那麼這個轉換規則是什麼呢?可以參考以下這個規則:
⚠️ 除了, ,
false
(空字元串),
""
,
null
, 和
undefined
,其餘的值都是轉成
NaN
true
也就是說,字元串
"false"
,
"0"
,以及空對象
{}
,空數組
[]
都是被轉成
true
。你可以用
Boolean
方法驗證下,例如
Boolean("0")
。在我們這個文章中,我們隻用到
轉成
false
。
基數
0 1 2 3 4 5 6 7 8 9 10
複制
當我們從一數到九,我們有不同的字元表示每個數字(0-9)。然而,當數到十的時候,我們用兩個字元表示(1和0)。這是因為我們采用的十進制,以10為基數(radix or base)。基數就是用一個字元表示的最小機關的數量。不同的計數方法有不同的基數,在不同的基數下一些相同的字元表示不同的數字。
十進制 二進制 十六進制
RADIX=10 RADIX=2 RADIX=16
0 0 0
1 1 1
2 10 2
3 11 3
4 100 4
5 101 5
6 110 6
7 111 7
8 1000 8
9 1001 9
10 1010 A
11 1011 B
12 1100 C
13 1101 D
14 1110 E
15 1111 F
16 10000 10
17 10001 11
複制
例如,看上面的表格,在不同的基數規則字元11可以表示不同的數字。如果基數是2,那麼11表示的是數字3,如果基數是16,那麼表示數字17。你可能注意到了,我們的例子中的11被
parseInt
後變成了3,也就是基數為2的時候。
Function arguments
Javascript中的function,不管聲明時是幾個變量,調用時可以傳任意個參數。沒有傳的預設為
undefined
,超出的部分被忽略(但會儲存在
arguments
對象中)。
function foo(x, y) {
console.log(x, y);
}
foo(1, 2); // 1 2
foo(1); // 1 undefined
foo(1, 2, 3); // 1 2
複制
map()
map
是數組
Array
的一個方法,傳回的是一個數組,這個數組的值是由原數組的每一個值通過一個新方法映射的。例如,下面的代碼就是把數組裡所有的數乘以3。
function multiplyBy3(x) {
return x * 3;
}
const result = [1, 2, 3, 4, 5].map(multiplyBy3);
console.log(result); // [3, 6, 9, 12, 15];
複制
現在我們可以用利用
map()
傳入
console.log
列印所有元素。
[1, 2, 3, 4, 5].map(console.log);
複制
哇?!發現列印的不僅僅是數值,還列印了index和整個數組。
[1, 2, 3, 4, 5].map(console.log);
// 相當于
[1, 2, 3, 4, 5].map(
(val, index, array) => console.log(val, index, array)
);
// 而不是
[1, 2, 3, 4, 5].map(
val => console.log(val)
);
複制
當傳入一個函數給map()時,對于每一個疊代器,都傳了3個參數給這個函數:
currentValue
(目前值),
currentIndex
(目前索引), 和
array
(原數組)。這就是為什麼會列印三個值了。好的?,我們現在已經揭開部分謎底了。
綜合起來看
parseInt
需要兩個參數:字元串和基數。當基數作為條件的時候是
false
時,基數預設為10。
parseInt('11'); // 11
parseInt('11', 2); // 3
parseInt('11', 16); // 17
parseInt('11', undefined); // 11 (基數 是 false)
parseInt('11', 0); // 11 (基數 是 false)
複制
現在,讓我們一步一步分解我們的例子:
['1', '7', '11'].map(parseInt); // [1, NaN, 3]
// 第一次疊代: val = '1', index = 0, array = ['1', '7', '11']
parseInt('1', 0, ['1', '7', '11']); // 1
複制
因為
Boolean(0)
為
false
,是以預設的基數為10。
parseInt
隻接收兩個參數,是以第三個參數
['1', '7', '11']
被忽略了。字元串
'1'
在基數10中為數字1。
// 第二次疊代: val = '7', index = 1, array = ['1', '7', '11']
parseInt('7', 1, ['1', '7', '11']); // NaN
複制
在基數1的系統中, 字元
'7'
不存在. 像第一次疊代一樣,最後一個參數被忽略。是以
parseInt
結果為
NaN
。
// 第三次疊代: val = '11', index = 2, array = ['1', '7', '11']
parseInt('11', 2, ['1', '7', '11']); // 3
複制
在基數2下(二進制)下,
'11'
表示數字3。最後一個參數被忽略。
總結
['1', '7', '11'].map(parseInt)
沒有像預期一樣是因為
map
在每次疊代傳了3個參數給
parseInt
。第二個參數
index
(目前索引)被
parseInt
作為基數參數了。是以,每個字元串被解析成不同的基數。
'7'
用基數1,傳回
NaN
,
'11'
用基數2,傳回
3
。因為
Boolean(0)
為
false
,
'1'
用預設基數10,傳回
1
。
是以,我們想要的結果應該是如下代碼:
['1', '7', '11'].map(numStr => parseInt(numStr));
複制