['1', '7', '11'].map(parseInt);
要想了解到底發生了什麼,我們首先要討論一些 JavaScript 的概念。如果你想要一個 TLDR(Too Long; Didn’t Read:太長了,不想讀),我在本文的末尾提供了一個快速總結。
下面是 JavaScript 中的一個簡單 if-else 語句:if (true) {
} else {
}
if ("hello world") {
console.log("Condition is truthy");
} else {
console.log("Condition is falsy");
}
嘗試在開發人員的控制臺(在 Chrome 上按 F12)中運行此代碼。我們會發現 if 塊運行了。這是因為字符串對象「hello world」是真。
每個 JavaScript 對象要麼是真,要麼是假。當將它們放到布爾上下文中時,如放在 if-else 語句中,對象將根據其真實性被視為 true 或 false。那麼哪些對象是真,哪些是假呢?這裡有一個簡單的規則:
除了 false、0、「」(空字符串)、null、undefined、及 NaN 以外, 所有值都是真。
令人困惑的是,這意味著字符串 「false」 、字符串 「0」 、空對象 {} 和空數組 [] 都是真。我們可以通過將一個對象傳遞到布爾函數中(例如 Boolean("0"); 中),來對其進行雙重檢查。
就我們的目的而言,只要記住 0 是假就足夠了。
基數
當我們從 0 數到 9 時,每個數字(0-9)都有不同的符號。然而,一旦達到 10,我們需要兩個不同的符號(1 和 0)來表示這個數字。這是因為我們的十進位計數系統的基數(或基礎)是 10。
基數是一個最小的數字,它只能由多個符號來表示。不同的計數系統有不同的基數,因此,相同的數字在不同的計數系統中,可以表示不同的數字。
十進位 二進位 十六進位
基數 =10 基數 =2 基數 =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 時,parseInt 返回 3,這對應於上表中的二進位列。
在 JavaScript 中,函數可以用任意數量的參數來調用,即使該數量不等於聲明函數時參數的數量。缺少的參數將被視為未定義,多餘的參數將被忽略(但是它們會被存儲在類似數組的參數對象中:https://javascriptweblog.wordpress.com/2011/01/18/javascripts-arguments-object-and-beyond/)。function foo(x, y) {
console.log(x);
console.log(y);
}
foo(1, 2);
foo(1);
foo(1, 2, 3);
到了我們要講的部分了!
Map 是數組原型中的一個方法,它返回一個新的數組,其中包含將原始數組的每個元素傳遞到函數中的結果。例如,下面的代碼將數組中的每個元素乘以 3:function multiplyBy3(x) {
return x * 3;
}
const result = [1, 2, 3, 4, 5].map(multiplyBy3);
console.log(result);
[1, 2, 3, 4, 5].map(console.log);
發生了一件非常奇怪的事情。每個 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 。如果提供的基數為假,那麼默認情況下,基數將被設置為 10。parseInt('11'); => 11
parseInt('11', 2); => 3
parseInt('11', 16); => 17
parseInt('11', undefined); => 11 (基數為假)
parseInt('11', 0); => 11 (基數為假)
['1', '7', '11'].map(parseInt); => [1, NaN, 3]
第一次第一次迭代 index = 0, array = ['1', '7', '11']
parseInt('1', 0, ['1', '7', '11']); => 1
// 第二次迭代 index = 1, array = ['1', '7', '11']
parseInt('7', 1, ['1', '7', '11']); => NaN
// 第三次迭代, 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' 按照默認基數 10 進行解析,因為它的索引 0 是假。
['1', '7', '11'].map(numStr => parseInt(numStr));
英文原文:https://medium.com/dailyjs/parseint-mystery-7c4368ef7b21