Array.map() 与 parseInt()
最近经常看到黑 Javascript 的人引用这样一个例子:
["1", "2", "3"].map(parseInt);
// 预期 [1, 2, 3]
// 结果 [1, NaN, NaN]
由于预期不一样,然后他们就各种炮轰 js。实际上这是一个误用,而这些人往往不愿深究其因,看客也把它当成一个笑柄,以讹转讹。但是只要用点心,就会发现其中的问题。
让我们先看看规范是如何定义 Array.map() 和 parseInt() 的吧:
¶Array.map()
MDN 给出了一个 Javascript 版的兼容方案,其返回结果与 native 相同,但方便我们理解 Array.map() 的工作机制。
map 是在最近的ECMA-262 标准中新添加的方法;所以一些旧版本的浏览器可能没有实现该方法. 在那些没有原生支持map 方法的浏览器中.你可以使用下面的javascript代码来实现它.所使用的算法正是 ECMA-262,第5版规定的. 假定Object, TypeError, 和 Array 有他们的原始值.而且callback.call的原始值也是 Function.prototype.call
// 实现 ECMA-262, Edition 5, 15.4.4.19
// 参考: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. 将O赋值为调用map方法的数组.
var O = Object(this);
// 2.将len赋值为数组O的长度.
var len = O.length >>> 0;
// 4.如果callback不是函数,则抛出TypeError异常.
if ({}.toString.call(callback) != "[object Function]") {
throw new TypeError(callback + " is not a function");
}
// 5. 如果参数thisArg有值,则将T赋值为thisArg;否则T为undefined.
if (thisArg) {
T = thisArg;
}
// 6. 创建新数组A,长度为原数组O长度len
A = new Array(len);
// 7. 将k赋值为0
k = 0;
// 8. 当 k < len 时,执行循环.
while(k < len) {
var kValue, mappedValue;
//遍历O,k为原数组索引
if (k in O) {
//kValue为索引k对应的值.
kValue = O[ k ];
// 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
mappedValue = callback.call(T, kValue, k, O);
// 返回值添加到新书组A中.
A[ k ] = mappedValue;
}
// k自增1
k++;
}
// 9. 返回新数组A
return A;
};
}
注意到 mappedValue = callback.call(T, kValue, k, O);
// 执行callback,this指向T,参数有三个.分别是kValue:值,k:索引,O:原数组.
实现上 callback 得到了三个参数,也就是说,如果使用 parseInt 作为回调函数的话,实际上是这样执行的:parseInt(kValue, k, O)
。这会出现什么问题呢?如果 parseInt 只使用一个参数的话,完全没有问题,但不巧的是,实际上 parseInt 接受两个参数(很多人不知道)。接下来我们看看 parseInt 的用法。
¶parseInt()
parseInt 以指定的底数将一个字符串解析为整数。
¶语法
parseInt(string, radix);
MDN 的文档建议无论何时都不要省略 radix
以免给读者带来困惑。很多开发者常常把 radix 省去,并希望 parseInt 能按他们的想法工作。实际上如果省略了 radix 会有很多意想不到的结果,它并不总是以10进制为底工作。有兴趣的话可以仔细读读这篇文档。
如何避免这种杯具呢?MDN 的中文页面有人补充了一个正确使用 Array.map() 和 parseInt() 的例子:
function returnInt(element){
return parseInt(element, 10);
}
["1", "2", "3"].map(returnInt);
// 返回[1,2,3]
###参考资料