本篇文章採用意譯,原文地址數組
你有沒有以爲 Javascript 是有點奇怪的。使用 map
和 parseInt
試着把字符串數組轉化成整型數組,看看會發生什麼。打開你的控制檯,粘貼下面的代碼而後執行。bash
['1', '7', '11'].map(parseInt);
複製代碼
沒有獲得 [1,7,11
,卻獲得了 [1, NaN, 3]
。這到底是怎麼回事?咱們首先須要討論一些 Javascript 的概念,若是你以爲太長,能夠跳到最後看總結。函數
一個簡單的 if-else 語句:ui
if (true) {
// this always runs
} else {
// this never runs
}
複製代碼
在這個例子中,條件爲真,執行 if 的語句塊,條件爲假執行 else 的語句塊。這是顯而易見的,由於 true 是個布爾值。咱們把非布爾值的東西做爲條件,會發生什麼?this
if ("hello world") {
// 它會運行嗎?
console.log("Condition is truthy");
} else {
// 它呢?
console.log("Condition is falsy");
}
複製代碼
在控制檯裏運行上面的代碼,你會發現 if 語句塊執行了。由於這個字符串對象是真值。spa
Javascript 對象要麼是真值要麼是假值。當在布爾值上下文中,好比 if-else 語句,對象被當作真或者假取決於它們的真實性。這個規則很簡單:日誌
除了:false, 0, ""(空字符串),null, undefined, 和 NaN
以外,其餘的都是真值。code
使人困惑的是,字符串 "false" 和 字符串 "0" 還有空對象 {}, 空數組 [],都是真值。你能夠經過給布爾函數傳值來進行雙向驗證,好比 Boolean("0")
。cdn
咱們的目的是,知道 0 是假值就足夠了。對象
0 1 2 3 4 5 6 7 8 9 10
複製代碼
當咱們從 0 數到 9 的時候,每一個不一樣的符號表明一個數字。然而到 10 的時候,咱們須要兩個符號來表示。這是由於咱們是十進制系統,它的基數是 10.
基數是用一個以上的符號表示的最小數字。不一樣的計數系統有着不一樣的基數。
DECIMAL BINARY HEXADECIMAL
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,它是 3,若是基數是 16,它是 17.
咱們上面的例子中吧 '11' 轉換成了 3,就是上面表格二進制的表現。
Javascript 中的函數能夠傳遞任意數量的參數,即便跟函數聲明的參數不相等。缺乏的參數會被當作 undefined,多餘的參數會被忽略(可是會存儲在類數組的 arguments 對象中)。
function foo(x, y) {
console.log(x);
console.log(y);
}
foo(1, 2); // logs 1, 2
foo(1); // logs 1, undefined
foo(1, 2, 3); // logs 1, 2
複製代碼
立刻就到咱們的重點了!
Map 是 Array 原型上的方法,它返回一個每一個原始數組的元素傳入函數的結果的新數組。好比下面代碼,每一個元素在數組中乘 3:
function multiplyBy3(x) {
return x * 3;
}
const result = [1, 2, 3, 4, 5].map(multiplyBy3);
console.log(result); // logs [3, 6, 9, 12, 15];
複製代碼
那麼如今若是我須要日誌輸出每一個元素,是否是使用 map()
而後傳入 console.log
就能夠了呢?
[1, 2, 3, 4, 5].map(console.log);
複製代碼
奇怪的事,不僅是輸出了值,同時把索引和所有數組也輸出了。
[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()
傳入一個方法時,對於每次迭代,都會有三個參數傳入方法:currentValue, currentIndex,
和所有 array
。這就是爲何每次迭代都會輸出所有三個實體內容。
如今離解開咱們的謎題愈來愈近了。
ParseInt
接受兩個參數:string
和 radix
。若是 radix 沒有提供,默認值就是 10.
parseInt('11'); => 11
parseInt('11', 2); => 3
parseInt('11', 16); => 17
parseInt('11', undefined); => 11 (沒有 radix)
parseInt('11', 0); => 11 (沒有 radix)
複製代碼
如今一步步走進以前的例子:
['1', '7', '11'].map(parseInt); => [1, NaN, 3]
// 第一次遍歷: val = '1', index = 0, array = ['1', '7', '11']
parseInt('1', 0, ['1', '7', '11']); => 1
複製代碼
由於 0 是假值,因此 radix 基數取值爲 10。 由於 parseInt 只接受兩個參數,因此第三個 ['1', '7', '11']
參數被忽略了。
// 第二次遍歷: 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 給 parseInt 傳遞了三個參數。第二個參數 index 做爲 radix 參數傳入了 parseInt。因此每一個數組的字符串使用了不一樣的基數來解析。'7' 被解析爲基數爲 1 的結果,也就是 NaN,11
被解析爲基數爲 2 的結果,也就是 3。1
被做爲默認值解析,由於索引 0 是假值。因此,下面的代碼才能正常工做:
['1', '7', '11'].map(numStr => parseInt(numStr));
複製代碼