原文作者:justjavac
JavaScript Puzzlers!被稱為 javascript 界的專業(yè)八級測驗睛蛛,感興趣的 jser 可以去試試鳄抒。
我試了一下, 36 道題只做對了 19 道, 算下來正確率為 53%忽肛,還沒有及格。
第一題為["1", "2", "3"].map(parseInt)的返回值栈暇。
> ?["1", "2", "3"].map(parseInt)
? ? [1, NaN, NaN]
在javascript中["1", "2", "3"].map(parseInt)為何返回不是[1,2,3]卻是[1,NaN,NaN]麻裁?
我們首先回顧一下parseInt()個map()兩個函數(shù)的用法:
parseInt() 函數(shù)
定義和用法
parseInt()函數(shù)可解析一個字符串,并返回一個整數(shù)源祈。
語法
parseInt(string, radix)
參數(shù) ? ? 描述
string 必需煎源。要被解析的字符串。
radix 可選:表示要解析的數(shù)字的基數(shù)香缺。該值介于 2 ~ 36 之間手销。
如果省略該參數(shù)或其值為 `0`,則數(shù)字將以 10 為基礎(chǔ)來解析图张。如果它以 `"0x"` 或 `"0X"` 開頭锋拖,將以 16 為基數(shù)。
如果該參數(shù)小于 2 或者大于 36祸轮,則 `parseInt()` 將返回 `NaN`兽埃。
返回值
返回解析后的數(shù)字。
說明
當(dāng)參數(shù)radix的值為0适袜,或沒有設(shè)置該參數(shù)時柄错,parseInt()會根據(jù)string來判斷數(shù)字的基數(shù)。
舉例:
1.如果string以"0x"開頭苦酱,parseInt()會把string的其余部分解析為十六進(jìn)制的整數(shù)售貌。
2.如果string以0開頭,那么 ECMAScript v3 允許parseInt()的一個實現(xiàn)把其后的字符解析為八進(jìn)制或十六進(jìn)制的數(shù)字疫萤。
3.如果string以 1 ~ 9 的數(shù)字開頭颂跨,parseInt()將把它解析為十進(jìn)制的整數(shù)。
提示和注釋
注釋:只有字符串中的第一個數(shù)字會被返回扯饶。
注釋:開頭和結(jié)尾的空格是允許的恒削。
提示:如果字符串的第一個字符不能被轉(zhuǎn)換為數(shù)字池颈,那么parseInt()會返回NaN。
實例
在本例中蔓同,我們將使用parseInt()來解析不同的字符串:
parseInt("10");// 返回 10 (默認(rèn)十進(jìn)制)
parseInt("19",10);// 返回 19 (十進(jìn)制: 10+9)
parseInt("11",2);// 返回 3 (二進(jìn)制: 2+1)
parseInt("17",8);// 返回 15 (八進(jìn)制: 8+7)
parseInt("1f",16);// 返回 31 (十六進(jìn)制: 16+15)
parseInt("010");// 未定:返回 10 或 8
map 方法
對數(shù)組的每個元素調(diào)用定義的回調(diào)函數(shù)并返回包含結(jié)果的數(shù)組饶辙。
array1.map(callbackfn[, thisArg])
參數(shù) ? ? ? ? ? ? ? ? ? ? ?定義
array1 ? ? ? ? ? ?必需蹲诀。一個數(shù)組對象斑粱。
callbackfn ? ? ? ? ?必需。一個接受**最多**三個參數(shù)的函數(shù)脯爪。對于數(shù)組中的每個元素则北,`map` 方法都會調(diào)用 `callbackfn` 函數(shù)一次。
thisArg ? ? ? ? ? 可選:可在 `callbackfn` 函數(shù)中為其引用 `this` 關(guān)鍵字的對象痕慢。如果省略 `thisArg`尚揣,則 `undefined` 將用作 `this` 值。
返回值
其中的每個元素均為關(guān)聯(lián)的原始數(shù)組元素的回調(diào)函數(shù)返回值的新數(shù)組掖举。
異常
如果callbackfn參數(shù)不是函數(shù)對象快骗,則將引發(fā)TypeError異常。
備注
對于數(shù)組中的每個元素塔次,map方法都會調(diào)用callbackfn函數(shù)一次(采用升序索引順序)方篮。 不為數(shù)組中缺少的元素調(diào)用該回調(diào)函數(shù)。
除了數(shù)組對象之外励负,map方法可由具有l(wèi)ength屬性且具有已按數(shù)字編制索引的屬性名的任何對象使用藕溅。
回調(diào)函數(shù)語法
回調(diào)函數(shù)的語法如下所示:
function callbackfn(value, index, array1)
可使用最多三個參數(shù)來聲明回調(diào)函數(shù)。
下表列出了回調(diào)函數(shù)參數(shù)继榆。
回調(diào)參數(shù) ?定義
value 數(shù)組元素的值巾表。
index 數(shù)組元素的數(shù)字索引。
array1 ? 包含該元素的數(shù)組對象略吨。
修改數(shù)組對象
數(shù)組對象可由回調(diào)函數(shù)修改集币。
下表描述了在map方法啟動后修改數(shù)組對象所獲得的結(jié)果。
`map` 方法啟動后的條件 元素是否傳遞給回調(diào)函數(shù)
在數(shù)組的原始長度之外添加元素翠忠【瞎叮 否。
添加元素以填充數(shù)組中缺少的元素负间∨佳 是,如果該索引尚未傳遞給回調(diào)函數(shù)政溃。
元素被更改趾访。 是董虱,如果該元素尚未傳遞給回調(diào)函數(shù)扼鞋。
從數(shù)組中刪除元素申鱼。 否云头,除非該元素已傳遞給回調(diào)函數(shù)捐友。
示例
下面的示例闡釋了map方法的用法。
// 定義回調(diào)函數(shù)
// 計算圓的面積
function AreaOfCircle(radius){
var area = Math.PI * (radius * radius);
return area.toFixed(0);?
}
// 定義一個數(shù)組溃槐,保護(hù)三個元素
var radii = [10, 20, 30];
// 計算 radii 的面積.
var areas = radii.map(AreaOfCircle);
document.write(areas);// 輸出:
// 314,1257,2827
下面的示例闡釋thisArg參數(shù)的用法匣砖,該參數(shù)指定對其引用this關(guān)鍵字的對象。
// 定義一個對象 object昏滴,保護(hù) divisor 屬性和 remainder 方法
// remainder 函數(shù)求每個傳入的值的個位數(shù)猴鲫。(即除以 10 取余數(shù))
var obj = {? ?
? divisor:10,? ?
? remainder: function(value){
returnvalue %this.divisor;? ??
}?
}
// 定義一個包含 4 個元素的數(shù)組
var numbers = [6,12,25,30];
// 對 numbers 數(shù)組的每個元素調(diào)用 obj 對象的 remainder 函數(shù)。
// map 函數(shù)的第 2 個參數(shù)傳入 ogj谣殊。
var result = numbers.map(obj.remainder, obj);
document.write(result);
// 輸出:
// 6,2,5,0
在下面的示例中拂共,內(nèi)置 JavaScript 方法用作回調(diào)函數(shù)。
// 對數(shù)組中的每個元素調(diào)用 Math.sqrt(value) (求平方根)
var numbers = [9,16];
var result = numbers.map(Math.sqrt);
document.write(result);
// 輸出: 3,4
[9, 16].map(Math.sqrt)回調(diào)函數(shù)姻几,輸出的結(jié)果是[3, 4]宜狐。
但是為什么["1", "2", "3"].map(parseInt)卻返回[1,NaN,NaN]?
網(wǎng)站給出的提示是:
what you actually get is[1, NaN, NaN]becauseparseInttakes two parameters(val, radix)andmappasses 3(element, index, array)
簡單翻譯一下就是
parseInt需要 2 個參數(shù)(val, radix)蛇捌, 而map傳遞了 3 個參數(shù)(element, index, array)」抚恒。
通過上面的解釋,我們可以看出豁陆,如果想讓parseInt(string, radix)返回 NaN柑爸,有兩種情況:
1.第一個參數(shù)不能轉(zhuǎn)換成數(shù)字。
2.第二個參數(shù)不在 2 到 36 之間盒音。
我們傳入的參數(shù)都能轉(zhuǎn)換成數(shù)字表鳍,所以只能是第二種可能。
到底是不是呢祥诽?我們重新定義parseInt(string, radix)函數(shù):
var parseInt = function(string, radix){
return string + "-" + radix;
};
["1", "2", "3"].map(parseInt);
輸出結(jié)果為:
["1-0", "2-1", "3-2"]
看見譬圣,map函數(shù)將數(shù)組的值value傳遞給了parseInt的第一個參數(shù),將數(shù)組的索引傳遞給了第二個參數(shù)雄坪。
第三個參數(shù)呢厘熟?我們再加一個參數(shù)
var parseInt = function(string, radix, obj){
return string + "-" + radix +"-"+ obj;
};
["1", "2", "3"].map(parseInt);
輸出結(jié)果:
["1-0-1,2,3", "2-1-1,2,3", "3-2-1,2,3"]
我們再繼續(xù)增加參數(shù):
var parseInt = function(string, radix, obj, other){
return string + "-" + radix +"-"+ obj +"-"+ other;
};
["1","2","3"].map(parseInt);
輸出結(jié)果:
["1-0-1,2,3-undefined", "2-1-1,2,3-undefined", "3-2-1,2,3-undefined"]
第四個參數(shù)為undefined,看見map確實為parseInt傳遞了三個參數(shù)维哈。就像作者寫道的:
(element, index, array)
1.數(shù)組的值
2.數(shù)組的索引
3.數(shù)組
UPDATE 原文勘誤:(謝謝米粽粽提醒)
["1", "2", "3"].map(parseInt)
應(yīng)該對應(yīng)的是:
[parseInt("1", 0), ?parseInt("2", 1), ?parseInt("3", 2)]
parseInt("3", 2)的第二個參數(shù)是界于 2-36 之間的绳姨,之所以返回NaN是因為 字符串"3"里面沒有合法的二進(jìn)制數(shù),所以NaN阔挠。
我們還可以繼續(xù)試驗:
> ["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]
只有當(dāng)?shù)诙€參數(shù)是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); // 十進(jìn)制 1
parseInt("2",1); // 第二個參數(shù)不在 2-36 直接
parseInt("3",2); // 二進(jìn)制 NaN
parseInt("4",3); // 三進(jìn)制
parseInt("5",4);
parseInt("6",5);
parseInt("7",6);
parseInt("8",7);
parseInt("9",8);
parseInt("10",9); // 九進(jìn)制 (1*9+0 = 9)
parseInt("11",10); // 十進(jìn)制 (1*10+1 = 11)
parseInt("12",11);
parseInt("13",12);
parseInt("14",13);
parseInt("15",14);
parseInt("16",15);
(全文完)