在循環(huán) for、for-in、forEach、for-of 、map中改變item的值,會發(fā)生什么?
真正開始寫業(yè)務邏輯,就離不開循環(huán)。而循環(huán)一直是編程中基礎的基礎。但是作為一個工作多年的前端程序員,一定還有人不了解循環(huán)的基礎知識。
下面我們一起來看看,在循環(huán)中如果改變了item的值會發(fā)生什么:
forEach
改變item本身
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
Symbol(),
'sss',
[4,4,4,4],
new Date()
]
list.forEach(item => {
item = 3
})
console.log(list)
[
{ name: 'a', count: 1 },
2,
[Function: fn],
Symbol(),
'sss',
[ 4, 4, 4, 4 ],
2022-09-13T10:40:17.322Z
]
我們發(fā)現(xiàn),基礎類型的幾個,string, number,Symbol()的內容都沒有發(fā)生變化。
改變item的屬性
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
Symbol(),
'sss',
[4,4,4,4],
new Date()
]
list.forEach(item => {
item.count = 3
})
console.log(list)
[ { name: 'a', count: 3 }, 2, [Function: fn] { count: 3 },
Symbol(),
'sss',
[ 4, 4, 4, 4, count: 3 ],
2022-09-13T10:41:26.631Z { count: 3 }
]
我們發(fā)現(xiàn):
基礎類型的,依舊沒有發(fā)生改變。
引用類型的變量,如果自身帶了count屬性,該屬性就會被修改;如果不帶該屬性,就會添加count屬性。
for
改變item本身
由于for 循環(huán)里,沒有專門的一個變量"item",可以獲取到對應的引用,我們只能用list[index]的形式去獲取到每一項。
我們運行看看效果。
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
[4,4,4,4],
new Date()
]
for (let i = 0; i < list.length; i ++) {
list[i] = 4
}
console.log(list)
[ 4, 4, 4, 4, 4 ]
全部被無差別覆蓋了。
改變item的屬性
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
[4,4,4,4],
new Date()
]
for (let i = 0; i < list.length; i ++) {
list[i].count = 4
}
console.log(list)
[
{ name: 'a', count: 4 },
2,
[Function: fn] { count: 4 },
[ 4, 4, 4, 4, count: 4 ],
2022-09-13T10:44:50.164Z { count: 4 }
]
我們發(fā)現(xiàn),和forEach的時候,表現(xiàn)一致:
基礎類型的,依舊沒有發(fā)生改變。
引用類型的變量,如果自身帶了count屬性,該屬性就會被修改;如果不帶該屬性,就會添加count屬性。
for-in
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
[4,4,4,4],
new Date()
]
for(let i in list) {
list[i] = 4
}
console.log(list)
[ 4, 4, 4, 4, 4 ]
for in 其實和for循環(huán)一致,因為他們都是取到了index,然后修改list[index]。
這里就不分別看改變item和改變item屬性了。
for of
改變item本身
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
[4,4,4,4],
new Date()
]
for(let i of list) {
i = 4
}
console.log(list)
[
{ name: 'a', count: 1 },
2,
[Function: fn],
[ 4, 4, 4, 4 ],
2022-09-13T10:56:11.711Z
]
我們發(fā)現(xiàn)item無法別更改。
改變item的屬性
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
[4,4,4,4],
new Date()
]
for(let i of list) {
i.count = 4
}
console.log(list)
[
{ name: 'a', count: 4 },
2,
[Function: fn] { count: 4 },
[ 4, 4, 4, 4, count: 4 ],
2022-09-13T10:57:36.085Z { count: 4 }
]
我們發(fā)現(xiàn):結果和forEach一致。他們都是在迭代函數(shù)里拿到了item。
map
改變item本身
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
Symbol(),
[4,4,4,4],
new Date()
]
list.map(item => {
item = 4
})
console.log(list)
[
{ name: 'a', count: 1 },
2,
[Function: fn],
Symbol(),
[ 4, 4, 4, 4 ],
2022-09-13T11:01:10.614Z
]
我們發(fā)現(xiàn),item無動于衷。
改變item的屬性
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
Symbol(),
[4,4,4,4],
new Date()
]
list.map(item => {
item.count = 4
})
console.log(list)
[
{ name: 'a', count: 4 },
2,
[Function: fn] { count: 4 },
Symbol(),
[ 4, 4, 4, 4, count: 4 ],
2022-09-13T10:59:53.050Z { count: 4 }
]
分析總結
方式 取值方式 改變自身 改變item的屬性
for list[index] 可以改變list[index] 基礎類型不可以引用類型可以
for-in list[index] 可以改變list[index] 基礎類型不可以引用類型可以
for-of item 不可以改變item 基礎類型不可以引用類型可以
forEach item 不可以改變item 基礎類型不可以引用類型可以
map item 不可以改變item 基礎類型不可以引用類型可以
為什么不可以改變屬性
改變自身和改變屬性,原因是一致的,就是分析一下,真正操作的數(shù)據(jù),到底是不是原數(shù)據(jù)本身。
這里,主要還是因為迭代器。
在for-of forEach map 方法中,其實item通過引用類型,指向了原來list里面的每一項。
我們來看細節(jié):
const list = [
{name: 'a', count: 1},
2,
function fn() {
console.log(3);
},
Symbol(),
'sss',
[4,4,4,4],
new Date()
]
const iter = list[Symbol.iterator]()
const firstElement = iter.next()
console.log(firstElement)
firstElement.value.count = 4
console.log(firstElement)
console.log(firstElement.value === list[0]);
{ value: { name: 'a', count: 1 }, done: false }
{ value: { name: 'a', count: 4 }, done: false }
true
對item進行操作,其實是對iterator.next() 指向的對象,也就是 iterator.next().value 進行了操作。
如果原來的值是引用類型,那么iterator.next().value 和 list[index] 表示的是同一個對象。操作的時候當然可以改變原來的item;
如果原來的值是基礎類型,那么iterator.next().value 和 list[index] 分別指向了一個基礎類型的值。操作的時候不會改變原來的item;
作者:碼出宇宙
歡迎關注微信公眾號 :碼出宇宙
掃描添加好友邀你進技術交流群,加我時注明【姓名+公司(學校)+職位】