前言
这几天在复习js数组的所有API,就是路易斯的 这篇文章,推荐看看! 到底怎么回事呢?当我复习到数组的12种遍历方式的时候,发现这么一句话 :
遍历方法(12个)
” 基于ES6,不会改变自身的方法一共有12个,分别为forEach、map、every、some、filter、reduce、reduceRight 以及ES6新增的方法entries、find、findIndex、keys、values。“
注意这个forEach
和map
!为什么它们不会改变原数组呢?我明明一直记得是可以的啊!
然后我就开始去论证我的观点吧,Let's go(来,si狗😂)。
例1:
const objArr1 = [{
name: 'hn',
age: 12
}]
const objArr2 = [{
name: 'wx',
age: 13
}]
objArr1.forEach(item => {
if (item.name === 'hn') {
item.age = 82
}
})
objArr2.map(item => {
if (item.name === 'wx') {
item.age = 83
}
})
console.log(objArr1); //[ { name: 'hn', age: 82 } ] 原数组被改变
console.log(objArr2); //[ { name: 'wx', age: 83 } ] 原数组被改变
论证结果
可以看出forEach和map确实能改变原数组啊!你以为这就完了?当然以我严谨的性格不可能就此结束的😄 我又在网上查询发现也有很多人遇到这个问题,恍然大悟!原来是我忽略了基本类型和引用类型!以为我平时用到forEavh和map基本都是引用数据类型(例如对象,数组等)。
举例分析
数据为基本类型
- 改变其值(不会改变)
const array = [1, 2, 3, 4];
array.forEach(item => {
item = item * 3
})
console.log(array); // [1,2,3,4]
数据为引用类型
- 改变其属性方法的值(会改变)
例子就是上面的例1!
- 改变整个单次循环的item (不会改变)
const changeItemArr = [{
name: 'hn1',
age: 12
}, {
name: 'hn2',
age: 13
}]
changeItemArr.forEach(item => {
if (item.name === 'hn2') {
item = {
name: 'hn3',
age: 77
}
}
})
console.log(changeItemArr); // [{name: "hn1", age: 12},{name: "hn2", age: 13}]
总结 JavaScript
是有基本数据类型与引用数据类型之分的。对于基本数据类型:number,string,Boolean,null,undefined
它们在栈内存中直接存储变量与值。而Object
对象的真正的数据是保存在堆内存,栈内只保存了对象的变量以及对应的堆的地址,所以操作Object
其实就是直接操作了原数组对象本身。
而在forEach
和map
方法中操作objArr1
和objArr2
,实际操作的是该对象在堆内存的地址,由于是对该地址所在的对象进行字段值修改,所以数组里的obj对象相应改变。
其实这让我联想到了另一个知识点,浅拷贝和深拷贝,浅拷贝就是对引用对象地址的拷贝,拷贝对象的改变也会引起被拷贝对象的改变。所以说知识点有时候是相通的🤗️。
扩展
常用解决方法
// 可以改变基本类型
const numArr = [13,4,15];
numArr.forEach((item, index, arr) => {
if (item === 13) {
arr[index] = 99
}
})
console.log(numArr); // [99, 4, 15]
// 也可以改变引用类型
const allChangeArr = [{
name: 'hn1',
age: 12
}, {
name: 'hn2',
age: 13
}]
allChangeArr.forEach((item, index, arr) => {
if (item.name === 'hn2') {
arr[index] = {
name: 'hn3',
age: 99
}
}
})
console.log(allChangeArr); // // [{name: "hn1", age: 12},{name: "hn3", age: 99}]
解析 你也许疑惑为什么通过arr[index]
就可以改变不管是基本还是引用类型的原数组了,原因是当调用forEach
和map
方法参数fn
传参是(item,index,arr),你是否还记得它们的参数fn
的参数包含三个分别是currentValue(必需。当前元素),index(可选。当前元素的索引值),arr(可选。当前元素所属的数组对象),重点就在arr
,它就是原数组啊,所有它自己还没权利改变自己吗?骚嘎寺内!😏