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

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

听说你精通循环,我不信

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

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

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

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

地址:前端面试题库

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;

 

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

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

地址:前端面试题库

相关文章
|
16天前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
54 20
用好PDCA循环法,轻松slay面试
如何在面试中完美发挥?可以借鉴PDCA循环法。P(Plan):规划面试策略和简历;D(Do):准备面试技巧、刷题等;C(Check):通过模拟面试提升表达能力;A(Act):复盘面试问题,查漏补缺,避免重复错误。这一科学方法有助于系统性地提升面试表现。
|
1月前
|
存储
`map()`方法在什么场景下会比 `forEach()`方法更高效?
综上所述,当需要对数组元素进行复杂的转换并生成新数组、进行链式调用和函数式编程、处理元素之间存在明确映射关系的情况以及与其他数组方法结合使用时,`map()`方法比`forEach()`方法更高效,能够使代码更加简洁、清晰和易于维护。
61 32
|
3月前
|
索引
ES5常见的数组方法:forEach ,map ,filter ,some ,every ,reduce (除了forEach,其他都有回调,都有return)
ES5常见的数组方法:forEach ,map ,filter ,some ,every ,reduce (除了forEach,其他都有回调,都有return)
|
1月前
|
存储 JavaScript 前端开发
如何选择使用`map()`方法和`forEach()`方法?
选择使用`map()`方法还是`forEach()`方法主要取决于操作的目的、是否需要返回值、代码的可读性和维护性等因素。在实际开发中,需要根据具体的业务需求和场景来灵活选择合适的方法,以实现更高效、更易读和更易维护的代码。
28 3
|
2月前
|
C语言
经典面试题:嵌入式系统中经常要用到无限循环,怎么样用C编写死循环呢
在嵌入式系统开发中,无限循环常用于持续运行特定任务或监听事件。使用C语言实现死循环很简单,可以通过`while(1)`或`for(;;)`的结构来编写。例如:`while (1) { /* 循环体代码 */ }`,这种写法明确简洁,适用于需要持续执行的任务或等待中断的场景。
|
3月前
|
存储 JavaScript 前端开发
`forEach()`方法和`map()`方法哪个执行效率更高?
`forEach()`方法和`map()`方法哪个执行效率更高?
|
3月前
数组方法中的`forEach()`方法和`map()`方法有什么区别?
数组方法中的`forEach()`方法和`map()`方法有什么区别?
|
3月前
|
JavaScript 前端开发
JavaScript 中 五种迭代数组的方法 every some map filter forEach
本文介绍了JavaScript中五种常用数组迭代方法:every、some、filter、map和forEach,并通过示例代码展示了它们的基本用法和区别。
|
1月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!