1. 前言
平时写代码的时候有没有发现一个问题觉得forEach是可以改变原数组的,但是有时候发现又不能改变原数组,此时是不是很迷了。but你有去仔细的分析数组中的每一项的类型吗?
你会发现能改变原数组的数组为对象数组,而不能改变的数组是数字字符串数组。根本原因在于前者是引用数据类型,后者为基本数据类型。
2. 讲解
- 改变原数组中引用数据类型
let a = 1
let obj = {'1':1}
let oldArr = ['1',1,obj,true,a]
oldArr.forEach((ele,index)=>{
if(typeof ele == 'object'){
ele['2']=2
}
})
console.log(oldArr) // [ '1', 1, { '1': 1, '2': 2 }, true, 1]
forEach方法只是操作数据而已,数组里的数据是如何引用的呢 ?js的数据有基本数据类型和引用数据类型,同时引出堆内存和栈内存的概念。对于基本数据类型:Number、String 、Boolean、Null、Undefined、Symbol、BigInt,它们在栈内存中直接存储变量名和值。而Object对象的真实数据存储在堆内存中,它在栈内存中存储的是变量名和堆内存的位置。 在forEach方法里操作的obj对象,实际操作的是该对象在堆内存的地址,由于是对该地址所在的对象进行字段值修改,所以数组里的obj对象相应改变。
基本数据类型与引用数据类型在堆栈中的位置如下图所示:
- 改变原数组中基本数据类型
let a = 1
let obj = {'1':1}
let oldArr = ['1',1,obj,true,a]
oldArr.forEach((ele,index,arr)=>{
arr[index] =2
})
console.log(oldArr) // [2,2,2,2,2]
- 不改变原数组中基本数据类型
let a = 1
let obj = {'key1':1}
let oldArr = ['1',1,obj,true,a]
oldArr.forEach((ele)=>{
if(typeof ele == 'object'){
ele['key2']=2
}
ele = 2
})
a = 2
console.log(oldArr) // ['1', 1, {key1: 1, key2: 2}, true, 1]
从例子来看forEach并不改变原数组,且直接在外面操作a变量也无法改变。 因为数组在创建后已在堆内存内生成了自己的值,数组中的变量已经成为具体的值,并非引用原变量在栈内存的地址。当我们使用forEach方法的时候对于每个数据都创建了一个变量ele,我们操作的是ele变量,对于基本数据类型,ele变量就是新创建的一个内存。ele变量改变并不影响原来地址值的改变。而ele变量对应的是引用数据类型时,实际还是一个引用地址,操作它,仍旧操作的是对应的堆内存。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/64742.html