JavaScript Puzzlers! 解惑(一):爲何 ["1", "2", "3"].map(parseInt) 返回 [1,NaN,NaN]?

JavaScript Puzzlers! 被稱爲 javascript 界的專業八級測驗,感興趣的 jser 能夠去試試。
我試了一下, 36 道題只作對了 19 道, 算下來正確率爲 53%,尚未及格。javascript

第一題爲 ["1", "2", "3"].map(parseInt) 的返回值。html

> ["1", "2", "3"].map(parseInt)
[1, NaN, NaN]

在 javascript 中 ["1", "2", "3"].map(parseInt) 爲什麼返回不是 [1,2,3] 倒是 [1,NaN,NaN]java

咱們首先回顧一下 parseInt()map() 兩個函數的用法:數組

parseInt() 函數

定義和用法

parseInt() 函數可解析一個字符串,並返回一個整數。app

語法

parseInt(string, radix)
參數 描述
string 必需。要被解析的字符串。
radix

可選。表示要解析的數字的基數。該值介於 2 ~ 36 之間。函數

若是省略該參數或其值爲 `0`,則數字將以 10 爲基礎來解析。若是它以 `"0x"` 或 `"0X"` 開頭,將以 16 爲基數。網站

若是該參數小於 2 或者大於 36,則 `parseInt()` 將返回 `NaN`。this

返回值

返回解析後的數字。翻譯

說明

當參數 radix 的值爲 0,或沒有設置該參數時,parseInt() 會根據 string 來判斷數字的基數。code

舉例:

  1. 若是 string"0x" 開頭,parseInt() 會把 string 的其他部分解析爲十六進制的整數。

  2. 若是 string0 開頭,那麼 ECMAScript v3 容許 parseInt() 的一個實現把其後的字符解析爲八進制或十六進制的數字。

  3. 若是 string 以 1 ~ 9 的數字開頭,parseInt() 將把它解析爲十進制的整數。

提示和註釋

註釋:只有字符串中的第一個數字會被返回。

註釋:開頭和結尾的空格是容許的。

提示:若是字符串的第一個字符不能被轉換爲數字,那麼 parseInt() 會返回 NaN

實例

在本例中,咱們將使用 parseInt() 來解析不一樣的字符串:

parseInt("10");         // 返回 10 (默認十進制)
parseInt("19",10);      // 返回 19 (十進制: 10+9)
parseInt("11",2);       // 返回 3 (二進制: 2+1)
parseInt("17",8);       // 返回 15 (八進制: 8+7)
parseInt("1f",16);      // 返回 31 (十六進制: 16+15)
parseInt("010");        // 未定:返回 10 或 8

map 方法

對數組的每一個元素調用定義的回調函數並返回包含結果的數組。

array1.map(callbackfn[, thisArg])
參數 定義
array1 必需。一個數組對象。
callbackfn 必需。一個接受**最多**三個參數的函數。對於數組中的每一個元素,`map` 方法都會調用 `callbackfn` 函數一次。
thisArg 可選。可在 `callbackfn` 函數中爲其引用 `this` 關鍵字的對象。若是省略 `thisArg`,則 `undefined` 將用做 `this` 值。

返回值

其中的每一個元素均爲關聯的原始數組元素的回調函數返回值的新數組。

異常

若是 callbackfn 參數不是函數對象,則將引起 TypeError 異常。

備註

對於數組中的每一個元素,map 方法都會調用 callbackfn 函數一次(採用升序索引順序)。 不爲數組中缺乏的元素調用該回調函數。

除了數組對象以外,map 方法可由具備 length 屬性且具備已按數字編制索引的屬性名的任何對象使用。

回調函數語法

回調函數的語法以下所示:

function callbackfn(value, index, array1)

可以使用最多三個參數來聲明回調函數。

下表列出了回調函數參數。

回調參數 定義
value 數組元素的值。
index 數組元素的數字索引。
array1 包含該元素的數組對象。

修改數組對象

數組對象可由回調函數修改。

下表描述了在 map 方法啓動後修改數組對象所得到的結果。

`map` 方法啓動後的條件 元素是否傳遞給回調函數
在數組的原始長度以外添加元素。 否。
添加元素以填充數組中缺乏的元素。 是,若是該索引還沒有傳遞給回調函數。
元素被更改。 是,若是該元素還沒有傳遞給回調函數。
從數組中刪除元素。 否,除非該元素已傳遞給回調函數。

示例

下面的示例闡釋了 map 方法的用法。

// 定義回調函數
// 計算圓的面積
function AreaOfCircle(radius) { 
    var area = Math.PI * (radius * radius); 
    return area.toFixed(0); 
} 

// 定義一個數組,保護三個元素
var radii = [10, 20, 30]; 

// 計算 radii 的面積. 
var areas = radii.map(AreaOfCircle); 

document.write(areas); 

// 輸出: 
// 314,1257,2827

下面的示例闡釋 thisArg 參數的用法,該參數指定對其引用 this 關鍵字的對象。

// 定義一個對象 object,保護 divisor 屬性和 remainder 方法
// remainder 函數求每一個傳入的值的個位數。(即除以 10 取餘數)
var obj = { 
    divisor: 10, 
    remainder: function (value) { 
        return value % this.divisor; 
    } 
} 

// 定義一個包含 4 個元素的數組
var numbers = [6, 12, 25, 30]; 

// 對 numbers 數組的每一個元素調用 obj 對象的 remainder 函數。
// map 函數的第 2 個參數傳入 ogj。 
var result = numbers.map(obj.remainder, obj); 
document.write(result); 

// 輸出: 
// 6,2,5,0

在下面的示例中,內置 JavaScript 方法用做回調函數。

// 對數組中的每一個元素調用 Math.sqrt(value) (求平方根)
var numbers = [9, 16]; 
var result = numbers.map(Math.sqrt); 

document.write(result); 
// 輸出: 3,4

[9, 16].map(Math.sqrt) 回調函數,輸出的結果是 [3, 4]
可是爲何 ["1", "2", "3"].map(parseInt) 卻返回 [1,NaN,NaN]

網站給出的提示是:

what you actually get is [1, NaN, NaN] because parseInt takes two parameters (val, radix) and map passes 3 (element, index, array)

簡單翻譯一下就是

parseInt 須要 2 個參數 (val, radix), 而 map 傳遞了 3 個參數 (element, index, array)」。


經過上面的解釋,咱們能夠看出,若是想讓 parseInt(string, radix) 返回 NaN,有兩種狀況:

  1. 第一個參數不能轉換成數字。

  2. 第二個參數不在 2 到 36 之間。

咱們傳入的參數都能轉換成數字,因此只能是第二種可能。

究竟是不是呢?咱們從新定義 parseInt(string, radix) 函數:

var parseInt = function(string, radix) {
    return string + "-" + radix;
};

["1", "2", "3"].map(parseInt);

輸出結果爲:

["1-0", "2-1", "3-2"]

看見,map 函數將數組的值 value 傳遞給了 parseInt 的第一個參數,將數組的索引傳遞給了第二個參數。
第三個參數呢?咱們再加一個參數

var parseInt = function(string, radix, obj) {
    return string + "-" + radix + "-" + obj;
};

["1", "2", "3"].map(parseInt);

輸出結果:

["1-0-1,2,3", "2-1-1,2,3", "3-2-1,2,3"]

咱們再繼續增長參數:

var parseInt = function(string, radix, obj, other) {
    return string + "-" + radix + "-" + obj + "-" + other;
};

["1", "2", "3"].map(parseInt);

輸出結果:

["1-0-1,2,3-undefined", "2-1-1,2,3-undefined", "3-2-1,2,3-undefined"]

第四個參數爲 undefined,看見 map 確實爲 parseInt 傳遞了三個參數。就像做者寫道的:

(element, index, array)
  1. 數組的值

  2. 數組的索引

  3. 數組

UPDATE 原文勘誤:(謝謝 米糉糉 提醒)

["1", "2", "3"].map(parseInt)

應該對應的是:

[parseInt("1", 0), parseInt("2", 1), parseInt("3", 2)]

parseInt("3", 2) 的第二個參數是界於 2-36 之間的,之因此返回 NaN 是由於 字符串 "3" 裏面沒有合法的二進制數,因此 NaN

咱們還能夠繼續試驗:

> ["1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1"].map(parseInt)
[1, NaN, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

只有當第二個參數是 1 的時候返回 NaN,其它狀況都返回 1

> ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"].map(parseInt)
[1, NaN, NaN, NaN, NaN, NaN, NaN, NaN, NaN, 9, 11, 13, 15, 17, 19, 21]

簡單列舉一下:

parseInt("1", 0);    // 十進制 1
parseInt("2", 1);    // 第二個參數不在 2-36 直接
parseInt("3", 2);    // 二進制 NaN
parseInt("4", 3);    // 三進制
parseInt("5", 4);
parseInt("6", 5);
parseInt("7", 6);
parseInt("8", 7);
parseInt("9", 8);
parseInt("10", 9);   // 九進制 (1*9+0 = 9)
parseInt("11", 10);  // 十進制 (1*10+1 = 11)
parseInt("12", 11);
parseInt("13", 12);
parseInt("14", 13);
parseInt("15", 14);
parseInt("16", 15);

(全文完)

文章來自個人我的博客:JavaScript Puzzlers 解密(一):爲何 ["1", "2", "3"].map(parseInt) 返回 [1, NaN, NaN]?

相關文章
相關標籤/搜索