让我们循环 - for...in 与 for...of 入门 For...of For...in For...in 和可迭代对象 我的古怪示例 就是这样

2025-05-25

循环 - for...in 与 for...of

入门

对于...的

对于...在

For...in 和可迭代对象

我的古怪例子

就是这样

不久前,我在使用Object.entries时,并没有看到我期望的功能。我盯着它看了又看,最后才意识到我用的是“for in”而不是“for of”。

这让我想到应该写一篇文章来谈谈它们之间的区别。于是,我们就在这里!

入门

for...infor...of是传统 for 循环的替代品。这类操作很常见。

for (let i = 0; i < arr.length; i++) {
  // do something here
}
Enter fullscreen mode Exit fullscreen mode

因此,迭代所有类型的数据结构的能力是一种很好的捷径。

对于...的

for...of专为数组和其他可迭代对象而设计。以下是示例。

let arr = [1, 2, 3]
for (item of arr) {
  console.log(item)
}
// 1
// 2
// 3
Enter fullscreen mode Exit fullscreen mode

请记住,JavaScript 中很多东西都是可迭代的,包括数组、字符串、map、set 等。

对于...在

另一方面,for...in可以处理对象。

let obj = {a:1, b:2, c:3}
for (item in obj) {
  console.log(item)
}
// a
// b
// c
Enter fullscreen mode Exit fullscreen mode

这里需要注意的是,它item实际上引用的是给定键值对的键。如果我们想访问值,可以这样做。

let obj = {a:1, b:2, c:3}
for (item in obj) {
  console.log(obj[item])
}
// 1
// 2
// 3
Enter fullscreen mode Exit fullscreen mode

For...in 和可迭代对象

事实证明,for...in可以处理可迭代对象以及对象。

let arr = [1, 2, 3]
for (idx in arr) {
  console.log(idx)
}
// 0
// 1
// 2
Enter fullscreen mode Exit fullscreen mode

它并不像对象那样引用键,而是引用数组中给定元素的索引。

如果我们想要访问元素本身,我们的代码将如下所示。

let arr = [1, 2, 3]
for (idx in arr) {
  console.log(arr[idx])
}
// 1
// 2
// 3
Enter fullscreen mode Exit fullscreen mode

我的古怪例子

因此,值得理解为什么上面的例子中两个版本都有效以及它们之间有什么区别。

我们将从开始for...of

请注意,如果您想复习一下这些概念,此示例使用了解构赋值Object.entries 。

对于...的

let obj = {a:1, b:2, c:3}
let newObj = {}
for (let [key, value] of Object.entries(obj)) {
  newObj[key] = value;
}
// newObj is { a: 1, b: 2, c: 3 }
Enter fullscreen mode Exit fullscreen mode

这可能有助于将其分解一点。Object.entries()正在将我们的obj变成多维数组表示。

[[a,1], [b,2], [c,3]]
Enter fullscreen mode Exit fullscreen mode

当我们遍历该数组时,我们会查看每个元素,它本身就是一个数组。

从那里开始,我们深入到该数组元素的下一级,并将名称分配key给第一个元素和value第二个元素。

最后,我们将这些键值对添加到newObj。这似乎按预期工作了。

那么会发生什么for...in

对于...在

let obj = {a:1, b:2, c:3}
let newObj = {}
for (let [key, value] in Object.entries(obj)) {
  newObj[key] = value;
}
// newObj is { 0: undefined, 1: undefined, 2: undefined }
Enter fullscreen mode Exit fullscreen mode

呃,什么?!我们来分析一下。

顺便说一句,现在您明白为什么这根本不是我所期望的结果了。

就像以前一样,Object.entries()给我们这个。

[[a,1], [b,2], [c,3]]
Enter fullscreen mode Exit fullscreen mode

然而,当我们遍历数组时,我们查看的是数组索引而不是值。所以我们的第一个条目是0,它没有[key, value]解构。key变成了0value并被赋予了 的值undefined

兔子洞

好的,我们稍后再回到正题,但我之前为了理解这个方法的原理,费了一番周折。如果我们把它分解到最基本的层面,这就是我们现在看到的代码。

const [key, value] = 0;
Enter fullscreen mode Exit fullscreen mode

这不合法!它会抛出TypeError: 0 is not iterable。那么为什么使用 时会出现这样的结果呢for...in

// key is 0
// value is undefined
Enter fullscreen mode Exit fullscreen mode

mozilla 文档中可以看出原因:
“数组索引只是具有整数名称的可枚举属性,并且与一般对象属性相同。”

它实际上不是一个像我们例子中那样0的类型,而是一个字符串!numberconst

因此,我们对解构内部发生的事情的超级深入示例[key, value]实际上是这样的。

let num = 0;
const [key, value] = num.toString();
// key is '0'
// value is undefined
Enter fullscreen mode Exit fullscreen mode

好的,回到正题

如果我们在我的示例中使用for...in并且我们想要我期望看到的东西,那么有一种方法可以得到它。

let obj = {a:1, b:2, c:3}
let newObj = {}
for (let idx in Object.entries(obj)){
    const [key, value] = Object.entries(obj)[idx]
    newObj[key] = value
}
// newObj is { a: 1, b: 2, c: 3 }
Enter fullscreen mode Exit fullscreen mode

然而,很明显for...of在这种情况下使用是更好的选择。

就是这样

拥有如此多的选择固然很好,但选择合适的工具也至关重要。否则,你最终会遇到一些意想不到的行为!

文章来源:https://dev.to/laurieontech/let-s-loop-for-in-vs-for-of-4loh
PREV
Nuxt、Next、Nest?!我的头好痛。
NEXT
我如何理解 RxJS