数组的 .map() 和 .forEach() 是否会修改原数组

面试的时候也算是进场会遇到的一个题目了,结论就是 可以也不可以,看原始数据是什么结构的,也看你如何是操作的。

如果说数组元素是基本类型的,比如说是数字类型、字符串、布尔类型的,那么不管是用 .map() 还是 .forEach() 都是无法修改原数组的。
如果说是集合类型的,比如说数组、对象,那么直接操作内部的元素或者属性都是会修改原数组的。

简单上一个 .forEach 的例子

const arr1 = [1, 2, 3]
arr1.forEach(item => item = 'a')
console.log(arr1)
// (3) [1, 2, 3]

const arr2 = ['a', 'b', 'c']
arr2.forEach(item => item = 1)
console.log(arr2)
// (3) ['a', 'b', 'c']

const arr3 = [{a:1}, {a:2}, {a:3}]
arr3.forEach(item => item.a = 'a')
console.log(arr3)
// (3) [{a: 'a'}, {a: 'a'}, {a: 'a'}]

const arr4 = [[1], [2], [3]]
arr4.forEach(item => item[0] = 'a')
console.log(arr4)
// (3) [['a'], ['a'], ['a']]

从以上例子里面可以很直接的看到结果,把 .forEach() 替换成 .map() 是一样的效果。说简单的一点就是深浅拷贝的问题, .forEach().map() 都只对第一层进行了复制,其内部的属性还是引用的内存地址。
所以其实是如果你是直接修改的整个元素就不会影响到原数组,比如说:

const arr = [{a:1}, {a:2}, {a:3}]
arr.forEach(item => item = {a:'a'})
console.log(arr)
// (3) [{a: 1}, {a: 2}, {a: 3}]

最开始的例子当中基本类型的修改不会影响到原数组也是由于这个机制,基本数据类型的复制是值的复制,复制后两者互相独立。

所以其实不只是 .map().forEach(),其他的会对数组进行遍历操作的API(.find().filter().every().some())也都有类似的问题。

相关阅读

Array.prototype.map() - JavaScript | MDN
Array.prototype.forEach() - JavaScript | MDN

ES6中forEach、map等方法会修改原数组吗? - 简书