
真正开始写业务逻辑,就离不开循环。而循环一直是编程中基础的基础。但是作为一个工作多年的前端程序员,一定还有人不了解循环的基础知识。
下面我们一起来看看,在循环中如果改变了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()的内容都没有发生变化。
- 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",可以获取到对应的引用,我们只能用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 ]
-
全部被无差别覆盖了。
- 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属性。
- 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属性了。
- 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无法别更改。
- 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。
- 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无动于衷。
- 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 进行了操作。
地址:前端面试题库