在循環(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;

作者:碼出宇宙


歡迎關注微信公眾號 :碼出宇宙

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