爲何 ['1', '7', '11'].map(parseInt) 返回 [1, NaN, 3]

翻譯 alentan數組

原文 medium.com/dailyjs瀏覽器

Javascript很奇怪。不相信我?嘗試使用map和parseInt將字符串數組轉換爲整數。啓動控制檯(Chrome上的F12),粘貼如下內容,而後按Enter

['1', '7', '11'].map(parseInt);
複製代碼

咱們最終獲得的不是一個[1, 7, 11] 這樣的整數數組,而是這樣的長這樣的 [1, NaN, 3] 一個數組。要了解到底發生了什麼,咱們首先要討論一些 Javascript 概念。若是你想要一個摘要(TLDR),我在本故事結尾處加入了一個快速摘要。bash

真值 & 假值

這是Javascript中一個簡單的if-else語句:函數

if (true) {
    // 永遠都會運行
} else {
    // 永遠不會運行
}
複製代碼

在這種狀況下,if-else 語句的條件爲 true,所以始終執行 if-block 語句塊並忽略 else-block 語句塊。這是一個簡單的例子,由於 true 是一個布爾值。若是咱們將非布爾值做爲條件會怎麼樣呢?ui

if ("hello world") {
    // 他會運行嗎?
    console.log("Condition is truthy");
} else {
    // 仍是運行這個?
    console.log("Condition is falsy");
}
複製代碼

嘗試在瀏覽器的控制檯中運行此代碼(Chrome上的F12)。您應該發現 if-block 語句塊運行。這是由於字符串對象"hello world"是true。spa

每一個Javascript對象當放置在布爾上下文中時都是真值或假值。例如 if-else 語句,會把Javascript對象轉爲true或false。那麼哪些對象是true的,哪些是false的呢?這是一個簡單的規則:翻譯

Javascript中當如下的值放置在布爾上下文中時會返回falsecode

false,0(""空字符串),null,undefined和NaN。cdn

進制(基數)

0 1 2 3 4 5 6 7 8 9 10
複製代碼

當咱們從0到9計數時,每一個數字(0-9)都有不一樣的符號。可是,一旦咱們達到10,咱們須要兩個不一樣的符號(1和0)來表示數字。這是由於咱們的小數計數系統的基數(或進制)爲10。對象

基數是最小的數字,只能由多個符號表示。不一樣的計數系統具備不一樣的基數,所以,相同的數字能夠指計數系統中的不一樣數字。

10進制    二進制    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中的函數可使用任意數量的參數調用,即便它們不等於聲明的函數參數的數量。缺乏的參數被視爲未定義,而多餘的參數會被忽略(但會存儲在相似數組的參數對象中)。

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()函數

咱們快到了!

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做爲一個參數傳遞給map()......

[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(進制)。若是提供的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是假的,所以進制(基數)設置爲默認值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,最後一個參數被忽略。

摘要(TLDR)

['1', '7', '11'].map(parseInt) 不能按預期工做,由於在每次迭代中 map 傳遞三個參數到 parseInt()。第二個參數 index 做爲radix(進制)參數傳遞給 parseInt 。所以,使用不一樣的進制(基數)解析數組中的每一個字符串。'7' 被解析爲進制(基數)爲 1,它是 NaN,'11' 被解析爲進制(基數)爲 2,它的值爲 3,'1' 被解析爲默認的進制(基數)爲 10,由於它的索引 0 是假值。

不知道你們想明白了沒有

相關文章
相關標籤/搜索