写 JS 代码用到的时候,以前我一般都用 for 或 for in ,少数情况下用 while ,后来 JS 的数组出了几个可用于循环的函数,但因为考虑兼容性问题,一开始我基本不用。 随着这些标准逐渐被支持,基本上不用考虑兼容性问题了,于是我就渐渐地试着用起这些函数来了。
用得最多的无疑是 map 和 forEach ,很多时候也只是需要循环一下,用哪个都差不多,于是看心情用 map 或 forEach ,但从函数名的长度来看,我当然会更倾向于使用 map 函数,但又因为写多了 PHP,习惯了 PHP 里的 foreach ,所以对 forEach 也有一定的好感。
不查资料我真的不知道这两个函数之间有什么区别,于是出于好奇,我还是去搜索了一下。
找到的结果基本都是这样的:
有些文章还给我举例来了:
说得头头是道,但这两个例子明显举得有问题,你发现了吗? 在用 forEach 的时候,是用:
value.id = index+1
这明显修改了 value 的值
而用 map 的时候 却是:
return { ...value ,id:index+1}
这里并没有去修改原数组的元素。
如果用 map 的时候,也是:
value.id = index+1
你看一下会不会修改到原数组?!
用 forEach:
var arr=[
{
id:1,
name:"hi"
},
{
id:2,
name:"he"
},
{
id:3,
name:"hello"
}
];
arr.forEach((v,i)=>{
v.name="_"+v.name;
v.age=i*10;
})
console.log(arr);
/*
[
{ id: 1, name: '_hi', age: 0 },
{ id: 2, name: '_he', age: 10 },
{ id: 3, name: '_hello', age: 20 }
]
*/
用 map:
var arr=[
{
id:1,
name:"hi"
},
{
id:2,
name:"he"
},
{
id:3,
name:"hello"
}
];
arr.map((v,i)=>{
v.name="_"+v.name;
v.age=i*10;
})
console.log(arr);
/*
[
{ id: 1, name: '_hi', age: 0 },
{ id: 2, name: '_he', age: 10 },
{ id: 3, name: '_hello', age: 20 }
]
*/
我们可以看到,使用 map 的时候,只要你在循环内修改了数组的元素,一样会影响到原数组,并不是很多地方说的 map 不会修改原数组。
当然,也有循环体内修改了元素,也不会对数组有影响的,比如:
var num=[1,2,3,4,5];
num.forEach((v,i)=>{
v=v+i;
})
console.log(num);//[1,2,3,4,5]
var num2=[1,2,3,4,5];
num2.map((v,i)=>{
v=v+i;
})
console.log(num2);//[1,2,3,4,5]
我们可以看到,尽管我在循环体内修改了元素:v=v+i;但原数据并没有被修改。
为什么呢? 其实有点 JS 常识的都应该知道,当数组的元素是对象时,就像我们把一个对象赋值给另一个变量,修改另一个变量是会影响到原变量的;而当一个变量是数字或字符串时则不会有影响。 所以,map 和 forEach 的区别根本和是否会修改到原数组没有关系。
它们最主要的区别是 map 有返回值,而 forEach 没有返回值。
我们再来看一段代码:
var num=[1,2,3,4,5];
var a=num.forEach((v,i)=>{
return v+i; //其实这里用不用 return ,效果都一样
})
console.log(a);//undefined
var num2=[1,2,3,4,5];
var b=num2.map((v,i)=>{
return v=v+i;
})
console.log(b);//[ 1, 3, 5, 7, 9 ]
所以,当我们只是需要一个循环,而不是需要通过一个数组去创建一个新的数组的时候,用 forEach 和 map 都可以,如果需要通过一个数组去创建一个新数组的话,用 map 。但需要注意的是,如果不想修改到原数组,当数组的元素是对象的时候,循环体内不要去修改它。 如果我们想通过修改旧数组得到一个新数组,但用 map 和 forEach 都可以。
但无论是 map 还是 forEach 在循环内都不能使用 break 或 return 去终于循环,如果你希望查找到某个元素后都退出循环的,那还是需要用回循环的语法,而不是数组迭代函数。