javascript中的parseInt与map函数都是常用的函数,可是 ["1", "2", "3"].map(parseInt) 为何返回不是[1,2,3]却是[1,NaN,NaN]?
这涉及到是否深入理解两个函数的格式与参数含义。
首先根据我对两个函数用法的了解,猜测是由于parseInt(string, radix) 的参数radix必须介于2~36之间,而且字符串string中的数字不能大于radix才能正确返回数字结果值。
我们通过以下javascript代码测试一下:
[javascript] view plaincopy
- var a=["1", "2", "3", "4","5",6,7,8,9,10,11,12,13,14,15];
- a.map(parseInt);
返回结果为:[1,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,9,11,13,15,17,19]
正好印证了以上的猜测是正确的,因为:
parseInt(‘1‘,0) = 1,
parseInt(‘2‘,1) = NaN,
parseInt(‘3‘,2) = NaN,
……
正是由于map的回调函数的参数index索引值作了parseInt的基数radix,导致出现超范围的radix赋值和不合法的进制解析,才会返回NaN。
也许你还会怀疑索引值和基数radix对应关系的准确性,这时你可以重新定义parseInt函数,再来测试一下:
[javascript] view plaincopy
- function parseInt(str, radix) {
- return str+‘-‘+radix;
- };
- var a=["1", "2", "3", "4","5",6,7,8,9,10,11,12,13,14,15];
- a.map(parseInt);
输出结果为:["1-0","2-1","3-2","4-3","5-4","6-5","7-6","8-7","9-8","10-9","11-10","12-11","13-12","14-13","15-14"]。
通过此例,再次证明,索引index的起始值从0开始,与radix的对应如前陈述一致,所以才会出现返回NaN的类型值。
这个实例提醒我们在使用两个函数parseInt和map时候要格外小心。同时对于IE6-7不支持map函数的情况也要谨慎或者通过prototype扩展处理。
最后再仔细回顾温习一下:
parseInt() 函数
定义和用法
parseInt() 函数可解析一个字符串,并返回一个整数。
语法
parseInt(string, radix)
参数 | 描述 |
---|---|
string | 必需。要被解析的字符串。 |
radix |
可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。 如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。 如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。 |
返回值
返回解析后的数字。
说明
当参数 radix 的值为 0,或没有设置该参数时,parseInt() 会根据 string 来判断数字的基数。
举例,如果 string 以 "0x" 开头,parseInt() 会把 string 的其余部分解析为十六进制的整数。如果string 以 0 开头,那么 ECMAScript v3 允许 parseInt() 的一个实现把其后的字符解析为八进制或十六进制的数字。如果string 以 1 ~ 9 的数字开头,parseInt() 将把它解析为十进制的整数。
提示和注释
注释:只有字符串中的第一个数字会被返回。
注释:开头和结尾的空格是允许的。
提示:如果字符串的第一个字符不能被转换为数字,那么 parseFloat() 会返回 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 方法 (Array) (JavaScript)
对数组的每个元素调用定义的回调函数并返回包含结果的数组。
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 方法的用法。
// Define the callback function.
function AreaOfCircle(radius) {
var area = Math.PI * (radius * radius);
return area.toFixed(0);
}
// Create an array.
var radii = [10, 20, 30];
// Get the areas from the radii.
var areas = radii.map(AreaOfCircle);
document.write(areas);
// Output:
// 314,1257,2827
下面的示例阐释 thisArg 参数的用法,该参数指定对其引用this 关键字的对象。
// Define an object that contains a divisor property and
// a remainder function.
var obj = {
divisor: 10,
remainder: function (value) {
return value % this.divisor;
}
}
// Create an array.
var numbers = [6, 12, 25, 30];
// Get the remainders.
// The obj argument specifies the this value in the callback function.
var result = numbers.map(obj.remainder, obj);
document.write(result);
// Output:
// 6,2,5,0
在下面的示例中,内置 JavaScript 方法用作回调函数。
// Apply Math.sqrt(value) to each element in an array.
var numbers = [9, 16];
var result = numbers.map(Math.sqrt);
document.write(result);
// Output: 3,4
map 方法可应用于字符串。 下面的示例阐释了这一点。
// Define the callback function.
function threeChars(value, index, str) {
// Create a string that contains the previous, current,
// and next character.
return str.substring(index - 1, index + 2);
}
// Create a string.
var word = "Thursday";
// Apply the map method to the string.
// Each array element in the result contains a string that
// has the previous, current, and next character.
// The commented out statement shows an alternative syntax.
var result = [].map.call(word, threeChars);
// var result = Array.prototype.map.call(word, threeChars);
document.write(result);
// Output:
// Th,Thu,hur,urs,rsd,sda,day,ay
在以下文档模式中受支持:Internet Explorer 9 标准模式、Internet Explorer 10 标准模式和 Internet Explorer 11 标准模式。Windows 应用商店 应用程序中也支持此项。请参阅版本信息。
在以下文档模式中不受支持:Quirks、Internet Explorer 6 标准模式、Internet Explorer 7 标准模式、Internet Explorer 8 标准模式。
最后再援引一篇文章:JavaScript数组遍历map()的原型扩展http://www.nowamagic.net/librarys/veda/detail/783
在 JavaScript 1.6 里,javascript 数组增加了几个非常有用的方法:indexOf、lastIndexOf、every、 filter、 forEach、 map、 some,其中前两个可以归为元素定位方法,而后面的几个则可以归为迭代(iterative)方法。
遗憾的是:这些新方法并非所有浏览器都支持,在这种情况下,我们就需要自己动手了,在这些介绍的文章中,我们同时提供了在不支持这些新特性的浏览器中的实现方法。
原生方法如下:
1 |
var mappedArray = array.map(callback[, thisObject]); |
- callback: 要对每个数组元素执行的回调函数。
- thisObject : 在执行回调函数时定义的this对象。
对数组中的每个元素都执行一次指定的函数(callback),并且以每次返回的结果为元素创建一个新数组。它只对数组中的非空元素执行指定的函数,没有赋值或者已经删除的元素将被忽略。
回调函数可以有三个参数:当前元素,当前元素的索引和当前的数组对象。如参数 thisObject 被传递进来,它将被当做回调函数(callback)内部的 this 对象,如果没有传递或者为null,那么将会使用全局对象。
map 不会改变原有数组,记住:只有在回调函数执行前传入的数组元素才有效,在回调函数开始执行后才添加的元素将被忽略,而在回调函数开始执行到最后一个元素这一期间,数组元素被删除或者被更改的,将以回调函数访问到该元素的时间为准,被删除的元素将被忽略。
如果浏览器不支持map方法,也可以按照下面的方式用prototype去扩展:
01 |
<script type= "text/javascript" > |
02 |
//扩展原型对象 |
03 |
Array.prototype.map = function (fn){ |
04 |
var a = []; |
05 |
for ( var i = 0; i < this .length; i++){ |
06 |
var value = fn( this [i], i); |
07 |
if (value == null ){ |
08 |
continue ; //如果函数fn返回null,则从数组中删除该项 |
09 |
} |
10 |
a.push(value); |
11 |
} |
12 |
return a; |
13 |
}; |
14 |
15 |
//例子,arr为原始数组 |
16 |
var arr = [ |
17 |
{name: ‘gonn‘ , age: 20, sex: ‘1‘ , No: ‘274200‘ }, |
18 |
{name: ‘nowamagic‘ , age: 30, sex: ‘0‘ , No: ‘274011‘ }, |
19 |
{name: ‘frie‘ , age: 40, sex: ‘1‘ , No: ‘274212‘ } |
20 |
]; |
21 |
|
22 |
//使用map更改数组每项的值,可对数组每一项元素内部进行增删改,也可以通过return null来删除数组的某项 |
23 |
var arr2 = arr.map( function (item, i){ |
24 |
item.sex = item.sex == ‘0‘ ? ‘女‘ : ‘男‘ ; |
25 |
if (item.name == ‘tom‘ ){ |
26 |
return null ; //删除name为tom的项 |
27 |
} |
28 |
return { |
29 |
index: i, |
30 |
name: item.name, |
31 |
age: item.age + 30 + i, |
32 |
sex: item.sex |
33 |
}; |
34 |
}); |
35 |
|
36 |
console.log(arr2); |
37 |
</script> |
在Firefox firebug控制台输出:
1 |
[ |
2 |
Object { index=0, name= "gonn" , age=50, 更多...}, |
3 |
Object { index=1, name= "nowamagic" , age=61, 更多...}, |
4 |
Object { index=2, name= "frie" , age=72, 更多...} |
5 |
] |
或者以下方式扩展也可以:
01 |
if (!Array.prototype.map) |
02 |
{ |
03 |
Array.prototype.map = function (fun /*, thisp*/ ) |
04 |
{ |
05 |
var len = this .length; |
06 |
if ( typeof fun != "function" ) |
07 |
throw new TypeError(); |
08 |
|
09 |
var res = new Array(len); |
10 |
var thisp = arguments[1]; |
11 |
for ( var i = 0; i < len; i++) |
12 |
{ |
13 |
if (i in this ) |
14 |
res[i] = fun.call(thisp, this [i], i, this ); |
15 |
} |
16 |
|
17 |
return res; |
18 |
}; |
19 |
} |
注:map返回的是新数组,它不修改调用的数组。
为了兼容不支持map的浏览器,developer.mozilla.org上给出了map兼容性解决方法。
[javascript] view plaincopy
- // Production steps of ECMA-262, Edition 5, 15.4.4.19
- // Reference: 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. Let O be the result of calling ToObject passing the |this| value as the argument.
- var O = Object(this);
- // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
- // 3. Let len be ToUint32(lenValue).
- var len = O.length >>> 0;
- // 4. If IsCallable(callback) is false, throw a TypeError exception.
- // See: http://es5.github.com/#x9.11
- if (typeof callback !== "function") {
- throw new TypeError(callback + " is not a function");
- }
- // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
- if (thisArg) {
- T = thisArg;
- }
- // 6. Let A be a new array created as if by the expression new Array(len) where Array is
- // the standard built-in constructor with that name and len is the value of len.
- A = new Array(len);
- // 7. Let k be 0
- k = 0;
- // 8. Repeat, while k < len
- while(k < len) {
- var kValue, mappedValue;
- // a. Let Pk be ToString(k).
- // This is implicit for LHS operands of the in operator
- // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
- // This step can be combined with c
- // c. If kPresent is true, then
- if (k in O) {
- // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
- kValue = O[ k ];
- // ii. Let mappedValue be the result of calling the Call internal method of callback
- // with T as the this value and argument list containing kValue, k, and O.
- mappedValue = callback.call(T, kValue, k, O);
- // iii. Call the DefineOwnProperty internal method of A with arguments
- // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
- // and false.
- // In browsers that support Object.defineProperty, use the following:
- // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
- // For best browser support, use the following:
- A[ k ] = mappedValue;
- }
- // d. Increase k by 1.
- k++;
- }
- // 9. return A
- return A;
- };
- }