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的值,原數組改變了。
