最近看mdn中 Array.prototype.map,以下为看的总结点

Array.prototype.map()

简介

map()方法创建一个新数组,其结果是该数组中每个元素都调用一个提供的函数后返回的结果
举例如下:

1
2
3
4
5
6
var Array1 = [1, 4, 9, 6];
// pass a function to map

const map1 = array1.map(x => x * 2);
console.log(map1);
// expected output: [2, 8, 18, 12]

语法

1
2
3
var newArray = arr.map(function callback(currentValue[, index[, array]])) {
return element for new_array
}[, thisArg]);

参数

1
callback

生成新的数组函数,使用三个参数

1
currentValue

callback数组中正在处理的当前元素.

1
index

(可选) callback 数组中正在处理的当前元素的索引.

1
array

(可选)执行callback函数时使用的this值。

返回值

一个新数组,每个元素都是回调函数的结果。

描述

map方法会给原数组中的每个元素都按顺序调用一次callback函数。callback每次执行后的返回值(包括undefined)组合起来形成一个新数组。callback函数只会在有值的索引上被调用;那些从来没被赋过值或者使用delete删除的索引则不会被调用。
callback 函数会被自动传入三个参数:数组元素、元素索引、原数组本身。
如果thisArg参数有值,则每次callback函数被调用的时候,this都会指向thisArg参数上的这个对象.如果省略了thisArg参数,后者赋值为null活undefined,则this指向全局对象。
map不修改调用它的原数组本身(当然可以在callback执行时改变原数组).
使用map方法处理数组时,数组元素的范围在callback方法第一次调用之前就已经确定了。在map方法执行的过程中:原数组中新增加的元素将不会被callback访问到;若已经存在的元素被改变或删除了,则他们的传递到callback的值map方法便利到它们的那一时刻的值;而被删除的元素不会被访问到。

示例

求数组中每个元素的平方根

下面的代码创建了一个新数组,值为原数组中对应数字的平方根

1
2
3
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1,2,3], numbers的值仍为[1,4,9]

使用map重新格式化数组中的对象

以下代码使用一个包含对象的数组来重新创建一个格式化的数组.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var kvArray = [{key: 1, value: 10},
{key: 2, value: 20},
{key: 3, value: 30},
];
var reformattedArray = kvArray.map(function(obj) {
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
// reforamttedArray 数组为: [{1: 10}, {2: 20}, {3: 30}];
// kvArray 数组未被修改
// [{key: 1, value: 10},
// {key: 2, value: 20},
// {key: 3, value: 30}]

使用一个包含一个参数的函数来mapping(构建)一个数字数组

下面的代码表示了当函数需要一个参数时map的工作方式。当map循环便利原始数组时,这个参数回自动被分配成数组中对应的每个元素。

1
2
3
4
5
6
7
var numbers = [1, 4, 9];
var doubles = numbers.map(function(item) => {
return num * 2;
});

// doubles数组的值为: [2, 8, 18];
// numbers数组未被修改 [1, 4, 9]

一般的map方法

下面的例子演示如何在一个String上使用map方法获取字符串中每个字符多对应的ASCII码组成的数组。

1
2
3
4
var map = Array.prototype.map;
var a = map.call('Hello World', function(x) {
return x.charCodeAt(0);
});

querySelectorAll 应用

下面代码展示了如何去遍历用querySelectorAll 得到的动态对象集合。在这里,我们获得了文档里所有选中的选项,并将其打印:

1
2
3
4
var elems =document.querySelectorAll('select option:checked');
var values = Array.prototype.map.call(elems. function(obj) {
return obj.value;
});

使用技巧案例

通常情况下,map方法中的callback函数只需要接受一个参数,就是正在被遍历的数组元素本身。但这并不意味着map只给callback传了一个参数。这个思维惯性可能会让我们犯一个很容易犯的错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 下面的语句返回什么呢:
['1', '2', '3'].map(parseInt);
// 你可能觉得会是 [1, 2, 3];
// 但实际结果是[1, NaN, NaN];

// 通常使用parseInt时,只需要传递一个参数
// 但实际上,parseInt可以有两个参数,第二个参数是进制数
// 可以通过语句 'alert(parseInt.length) === 2'来验证
// map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素,元素索引,原数组本身。
// 第三个参数parseInt 会忽视,但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用,从而返回了NaN

function returnInt (element) {
return parseInt(element, 10);
}

['1', '2', '3'].map(returnInt); // [1, 2, 3] 意料之中的结果

// 也可以使用简单的箭头函数,结果同上
['1', '2', '3'].map( str => parseInt(str));

// 一个简单的方式:
['1', '2', '3'].map(Number); // [1, 2, 3]

// 与`parseInt`不同,下面的结果会返回浮点数或指数
['1.1', '2.2e2', '3e300'].map(Number); // [1.1, 220, 3e+300]

Polyfill

map是在最近的ECMA-262 标准中新添加的方法;所以一些旧版本的浏览器可能没有实现该方法。在那些没有原生支持map方法的浏览器中,你可以使用下面的Javascript代码来实现它。所使用的算法正式ECMA-262,第五版规定的。假定Object,TypeError, 和Array有他们的原始值。而且callback.call的原始值也是Function.prototype.call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 实现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.将0赋值为调用map方法的数组
var 0 = Object(this);

// 2.将len赋值为数组0的长度
var len = 0.length >>> 0;


// 3.如果callback 不是函数,则跑出TypeError异常
if (Object.prototype.toString.call(callback) != '[object Function]') {
throw new TypeError(callback + ' is not a function');
}

// 4. 如果参数thisArg有值,则将T赋值为thisArg;
if (thisArg) {
T = thisArg;
}

// 5. 创建新数组A,长度为原数组0长度len
A = new Array(len);

// 6. 将k赋值为0
k = 0;

// 7. 当k < len时,执行循环
while(k < len) {
var kValue, mappedValue;
// 遍历0,k为原数组索引
if (k in 0) {
// kValue为索引k对应的值
kValue = 0[k];

// 执行callback,this指向T,参数有三个,分别是kValue:值,k:索引,0:原数组
mappedValue = callback.call(T,kValue,k,0);
// 返回值添加到新数组A中
A[k] = mappedValue;

}
// k自增1
k ++;
}
// 返回新数组
return A;
};
}