在循環(huán) for、for-in、forEach、for-of 、map中改變item的值,會(huì)發(fā)生什么?

真正開始寫業(yè)務(wù)邏輯,就離不開循環(huán)。而循環(huán)一直是編程中基礎(chǔ)的基礎(chǔ)。但是作為一個(gè)工作多年的前端程序員,一定還有人不了解循環(huán)的基礎(chǔ)知識(shí)。

下面我們一起來看看,在循環(huán)中如果改變了item的值會(huì)發(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),基礎(chǔ)類型的幾個(gè),string, number,Symbol()的內(nèi)容都沒有發(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):

基礎(chǔ)類型的,依舊沒有發(fā)生改變。

引用類型的變量,如果自身帶了count屬性,該屬性就會(huì)被修改;如果不帶該屬性,就會(huì)添加count屬性。

for

改變item本身

由于for 循環(huán)里,沒有專門的一個(gè)變量"item",可以獲取到對(duì)應(yīng)的引用,我們只能用list[index]的形式去獲取到每一項(xiàng)。

我們運(yùn)行看看效果。

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的時(shí)候,表現(xiàn)一致:

基礎(chǔ)類型的,依舊沒有發(fā)生改變。

引用類型的變量,如果自身帶了count屬性,該屬性就會(huì)被修改;如果不帶該屬性,就會(huì)添加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 其實(shí)和for循環(huán)一致,因?yàn)樗麄兌际侨〉搅薸ndex,然后修改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):結(jié)果和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無動(dòng)于衷。

改變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 }
]

分析總結(jié)

方式    取值方式    改變自身    改變item的屬性
for    list[index]    可以改變list[index]    基礎(chǔ)類型不可以引用類型可以
for-in    list[index]    可以改變list[index]    基礎(chǔ)類型不可以引用類型可以
for-of    item    不可以改變item    基礎(chǔ)類型不可以引用類型可以
forEach    item    不可以改變item    基礎(chǔ)類型不可以引用類型可以
map    item    不可以改變item    基礎(chǔ)類型不可以引用類型可以

為什么不可以改變屬性

改變自身和改變屬性,原因是一致的,就是分析一下,真正操作的數(shù)據(jù),到底是不是原數(shù)據(jù)本身。

這里,主要還是因?yàn)榈鳌?br>
在for-of forEach map 方法中,其實(shí)item通過引用類型,指向了原來list里面的每一項(xiàng)。

我們來看細(xì)節(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
對(duì)item進(jìn)行操作,其實(shí)是對(duì)iterator.next() 指向的對(duì)象,也就是 iterator.next().value 進(jìn)行了操作。

如果原來的值是引用類型,那么iterator.next().value 和 list[index] 表示的是同一個(gè)對(duì)象。操作的時(shí)候當(dāng)然可以改變?cè)瓉淼膇tem;

如果原來的值是基礎(chǔ)類型,那么iterator.next().value 和 list[index] 分別指向了一個(gè)基礎(chǔ)類型的值。操作的時(shí)候不會(huì)改變?cè)瓉淼膇tem;

作者:碼出宇宙


歡迎關(guān)注微信公眾號(hào) :碼出宇宙

掃描添加好友邀你進(jìn)技術(shù)交流群,加我時(shí)注明【姓名+公司(學(xué)校)+職位】