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

47 阅读2分钟

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 = listSymbol.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;


 


## 给大家推荐一个实用面试题库


#### **1、前端面试题库 (**面试必备) ****推荐:★★★★★****


地址:[前端面试题库]( )