0
点赞
收藏
分享

微信扫一扫

【面试题】在循环 for、for-in、forEach、for-of 、map中改变item的值,会发生什么?


【面试题】在循环 for、for-in、forEach、for-of 、map中改变item的值,会发生什么?_前端

听说你精通循环,我不信

真正开始写业务逻辑,就离不开​​循环​​​。而​​循环​​一直是编程中基础的基础。但是作为一个工作多年的前端程序员,一定还有人不了解循环的基础知识。

下面我们一起来看看,在循环中如果改变了item的值会发生什么:


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
]

我们发现,基础类型的几个,string, number,Symbol()的内容都没有发生变化。

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

我们发现:

  • 基础类型的,依旧没有发生改变。
  • 引用类型的变量,如果自身带了count属性,该属性就会被修改;如果不带该属性,就会添加count属性。

for

改变item本身

由于for 循环里,没有专门的一个变量"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 }
]

我们发现,和forEach的时候,表现一致:

  • 基础类型的,依旧没有发生改变。
  • 引用类型的变量,如果自身带了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循环一致,因为他们都是取到了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
]

我们发现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 }
]

我们发现:结果和forEach一致。他们都是在迭代函数里拿到了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
]

我们发现,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

基础类型不可以引用类型可

 

为什么不可以改变属性

改变自身和改变属性,原因是一致的,就是分析一下,真正操作的数据,到底是不是原数据本身。

这里,主要还是因为迭代器。

在for-of forEach map 方法中,其实item通过引用类型,指向了原来list里面的每一项。

我们来看细节:

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;

 


举报

相关推荐

0 条评论