Map 和 forEach 区别
.forEach和map的相同点
1.都是数组的方法+都是用来遍历数组
2.两个函数都有4个参数:匿名函数中可传3个参数item(当前项),index(当前项的索引),arr(原数组),还有一个可选参数this
3.匿名函数中的this默认是指向window的
4.对空数组不会调用回调函数
5.不会改变原数组(某些情况下可改变)
Map
1.map接收后三个参数(1.当前值,2.当前值下标,3.原始数组[ ])
const arr = ['1', '2', '3'];
const cb = (str, i, origin) =>
{ console.log(`${i}: ${Number(str)} / ${origin}`); };
arr.map(cb);
Map单独作为回调函数使用
arr.map((str) => { console.log(Number(str)); }) //1,2,3
- Map会创建一个新数组,创建新空间,接受原始数组
(1)返回一个经过处理后的新数组,但不改变原数组
var a=[1,2,3,4,5]
var b=a.map((item)=>{
return item=item*2 //需要创建返回值接收值
})
console.log(a)//[1,2,3,4,5]
console.log(b)//[2,4,6,8,10]
(2)map中可改变原数组的情况和原理与forEach相同
forEach
1)没有返回值
var a=[1,2,3,4,5]
var b=a.forEach((item)=>{
item=item*2
})
console.log(b)//undefined
//1.不能创建新数组,没有返回值
item的值并不是相应的原数组中的值,而是重新建立的一个新变量,值和原数组相同。
//简单来说forEach((item)=>{})
item是从a[]数组里面复制出来的与a[]中每一项值都一样的新变量,并不是原数组a[],
所以item改变仅改变item 复制出来的自己这个新变量,对原数组,堆内存都没有影响,
(2)可改变原数组的情况
var a=[1,2,3,4,5]
a.forEach(item)=>{
item=item*2
}
console.log(a)//[1,2,3,4,5]
//2改变复制出的新变量
//数组中的对象的值也没有改变,是因为新创建的变量和原数组中的对象虽然指向同一个地址,但改变的是新变量的值,即新对象的值为2,原数组中的对象还是{num:1}。
var a=[1,'1',{num:1},true]
a.forEach((item,index,arr)=>{
item=2
})
console.log(a)//[1,'1',{num:1},true]
这里修改item值,依然没有修改原数组
var a=[1,'1',{num:1},true]
a.forEach((item,index,arr)=>{
item.num=2
item=2
})
console.log(a)//[1,'1',{num:2},true]
当修改数组中的对象的某个属性时,发现属性改变了。
//直接在数组上, 用.的方法 找到新对象指向的引用类型地址
由于对象是引用类型,新对象和旧对象指向的都是同一个引用地址,所以新对象把num变成了2,原数组中的对象也改变了。
为什么会这样呢?
这里就要引入栈(stack)内存和堆(heap)内存的概念了,
如String,Number,Boolean,Undefined,Null是存在于栈内存中的,在栈内存中储存变量名及相应的值。
Object,Array,Function存在于堆内存中,在堆内存中储存变量名及引用位置。
想要修改原数组借助回调参数里的办法
var a = [1,2,3,4,5]
a.forEach((item, index, arr) => {
arr[index] = item * 2
})
console.log(a)
// [2,4,6,8,10]
//在回调函数里改变arr的值,原数组改变了。