["1", "2", "3"].map(parseInt)得到什么?
答案是:[1, NaN, NaN].
原因:主要是下面這3點
1. map函數傳遞參數的定義
2. parseInt函數針對於radix這個參數的理解
3. 二進制當中沒有"3"這個數碼
接下來具體看一下是為什么
-------------------------------------------------分割線------------------------------------------------------------------
昨天收到網友的留言,覺得確實之前的思路有一點亂,這里整理一下思路,重新寫一下。希望可以幫助到后面看到這篇文章的同學。
這個問題我們最開始可能以為的答案會是
[1, 2, 3]
為什么會產生這種想法,因為我們通常使用map函數的時候都會傳入一個函數,這個函數一般只使用1-2個參數,如下所示:
var arr = ["1", "2", "3"].map(function(item){ // 這個地方只傳入一個參數 return item; }); console.log(arr); // ["1", "2", "3"]
var arr = ["1", "2", "3"].map(function(item, index){ // 這個地方傳入兩個參數 return "value:" + item + ", index:" + index; }); console.log(arr); // ["value:1, index:0", "value:2, index:1", "value:3, index:2"]
可以看到,其實得到的結果取決於傳進去的參數,還有function函數的執行過程。
標准定義下,map方法會傳遞3個參數
arr.map(function(item, index, arr){ ..... });
這個時候,題目中的問題就轉化為下面的函數求解
var arr = ["1","2","3"]; arr.map((value,index,array) => parseInt(value,index)); //parseInt(string,radix)
這個前提是,我們需要知道parseInt函數本身是怎么定義的?
接下來看一下parseInt的官方定義
parseInt(string, radix);
string: 需要轉化的字符,如果不是字符串會被轉換,忽視空格符。
radix:數字2-36之前的整型。默認使用10,表示十進制。這個參數的意義是指把前面的字符看作是多少進制的數字,所謂的基數。
如下所示:
// 將'123'看作5進制數,返回十進制數38 => 1*5^2 + 2*5^1 + 3*5^0 = 38 parseInt('123', 5)
需要注意的是,如果radix在2-36之外會返回NaN。
在沒有指定基數,或者基數為 0 的情況下,JavaScript 作如下處理:
- 如果字符串
string
以"0x"或者"0X"開頭, 則基數是16 (16進制). - 如果字符串
string
以"0"開頭, 基數是8(八進制)或者10(十進制),那么具體是哪個基數由實現環境決定。ECMAScript 5 規定使用10,但是並不是所有的瀏覽器都遵循這個規定。因此,永遠都要明確給出radix參數的值。 - 如果字符串
string
以其它任何值開頭,則基數是10 (十進制)。
因為parseInt只接收2個參數,因此map的callback函數就只傳遞(item, index)這兩個值給parseInt。
那么上面的函數就可以分解為求解下面這三個函數的值,並返回結果
parseInt('1', 0); // 1 (parseInt的處理方式,這個地方item沒有以"0x"或者"0X"開始,8和10這個基數由實現環境來定,ES5規定使用10來作為基數,因此這個0相當於傳遞了10) parseInt('2', 1); // NaN (因為parseInt的定義,超出了radix的界限) parseInt('3', 2); // NaN (雖然沒有超出界限,但是二進制里面沒有3,因此返回NaN)
再重復總結一下這道題的三個考點:
1. map函數傳遞參數的定義,此處本身map函數是有3個參數可以傳遞的
2. parseInt函數針對於radix這個參數的理解,針對於0,2-36以外界限的定義
3. 二進制當中沒有"3"這個數碼
我想結合我上面的分析,再加上我下面的一些知識補充,應該可以對這個問題有一個很清晰的認識了吧~
------------------------------------------------------------------------------------------------------------------------
map函數定義:
arr.map(callback[,thisArg]);
callback
原數組中的元素經過該方法后返回一個新的元素。
thisArg可選. callback函數里的this值 默認是window對象
下面我們將parseInt重新定義,看一下會返回什么?
執行下面的函數:
var parseInt = function (string, radix, others) { return string + '-' + radix + '-' + others; }; ['1','2','3'].map(parseInt);
為什么會得到這個數組:以數組第一個字符串為例,1-0-1,2,3是因為map的callback返回參數分別是currentValue:1,index:0,array:[1,2,3](此處被轉義)。
其他同上。那么接下來,我們將map函數執行原始parseInt函數拆分執行:
parseInt函數定義:
parseInt(string, radix);
string: 需要轉化的字符,如果不是字符串會被轉換,忽視空格符。
radix:數字2-36之前的整型。默認使用10,表示十進制。
需要注意的是,如果radix在2-36之外會返回NaN。
因為parseInt函數接收2個參數,string,radix,如果map函數返回了這兩個參數,不管意義是否是所期望的,都會將其作為參數執行。
以1-0-1,2,3為例,map(parseInt)中,parseInt作為callback函數執行的將是:parseInt('1',0)(前面那個數字1自動被轉換為字符串1),其他同上。
看下面的執行函數結果
parseInt('1', 0); parseInt('2', 1); parseInt('3', 2);
所以得到1,NaN,NaN
因此,在最開始的題目["1", "2", "3"].map(parseInt)得到的是1,NaN,NaN。
(此處如果出錯,主要是對map的callback返回參數和parseInt會接受2個參數的不熟悉)
Map函數的其他用途:
例1:遍歷querySelectorAll對象,並執行相關函數
var elems = document.querySelectorAll('div'); var values = Array.prototype.map.call(elems, function (elem) { return elem; });
例2:反轉字符串
var str = '12345'; Array.prototype.map.call(str, function(x){ return x; }).reverse().join();
還有一種翻轉字符的方法:
var str = '12345'; var strre = str.split('').reverse().join('');
附:這個方法可以判斷回文
var str = '12345'; var str1 = Array.prototype.map.call(str, function(x){ return x; }).reverse().join(); if (str === str1) { console.log('true'); } else { console.log('false'); }