ChatGPT解决这个技术问题 Extra ChatGPT

在 JavaScript 中使用 for...of 语法获取循环计数器/索引

注意:问题仍然适用于 for...of 循环。> 不要使用 for...in 来迭代数组,用它来迭代对象的属性。也就是说,这

我了解 JavaScript 中的基本 for…in 语法如下所示:

for (var obj in myArray) {
    // ...
}

但是如何获得循环计数器/索引?

我知道我可能会做类似的事情:

var i = 0;
for (var obj in myArray) {
    alert(i)
    i++
}

甚至是老好人:

for (var i = 0; i < myArray.length; i++) {
    var obj = myArray[i]
    alert(i)
}

但我宁愿使用更简单的 for-in 循环。我认为它们看起来更好,更有意义。

有没有更简单或更优雅的方法?

在 Python 中很容易:

for i, obj in enumerate(myArray):
    print i
不要将 for...in 用于数组。无论如何,它会遍历属性名称,而不是属性的值。
它是一个数组,而不是一个对象,对吧?那么,alert(obj)

R
Ry-

for…in 迭代属性名称,而不是值,并且这样做 in an unspecified order(是的,即使在 ES6 之后也是如此)。您不应该使用它来迭代数组。对他们来说,有 ES5 的 forEach 方法将值和索引都传递给你给它的函数:

var myArray = [123, 15, 187, 32];

myArray.forEach(function (value, i) {
    console.log('%d: %s', i, value);
});

// Outputs:
// 0: 123
// 1: 15
// 2: 187
// 3: 32

或者 ES6 的 Array.prototype.entries,它现在支持当前浏览器版本:

for (const [i, value] of myArray.entries()) {
    console.log('%d: %s', i, value);
}

对于一般的可迭代对象(您将使用 for…of 循环而不是 for…in),没有内置任何内容,但是:

function* enumerate(iterable) {
    let i = 0;

    for (const x of iterable) {
        yield [i, x];
        i++;
    }
}

for (const [i, obj] of enumerate(myArray)) {
    console.log(i, obj);
}

demo

如果您确实是指 for…in – 枚举属性 – 您将需要一个额外的计数器。 Object.keys(obj).forEach 可以工作,但它只包含 自己的 属性; for…in 包括原型链上任意位置的可枚举属性。


哦好的。我很困惑。我认为 JavaScript 的 for-in 与 Python 的相同。感谢您的澄清。
@quantumpotato:let 是具有块范围的 varconst 不变。
这是一个详细的答案,谢谢。真正澄清了所有讨论的事情
愚蠢的问题,但 %d 和 %s 实际上代表什么,或者它们可以是我希望它们成为的任何字母吗?
@klewis:%d 格式化整数,%s 格式化字符串。它们基于 printfconsole.spec.whatwg.org/#formatter 正在制定规范。
m
mikemaccana

在 ES6 中,最好使用 for... of 循环。您可以像这样在 for... of 中获取索引

for (let [index, val] of array.entries()) {
  // your code goes here    
}

请注意,Array.entries() 返回 an iterator,这使得它可以在 for-of 循环中工作;不要将此与 Object.entries() 混淆,后者返回一个键值对的数组


这是一个比接受的答案更好的答案!
我认为这个解决方案比 forEach 更好...它使用常规的 for...of 循环语法,您不必使用单独的函数。换句话说,它在语法上更好。 OP似乎想要这个。
entries() 返回一个空对象:{}。知道为什么会这样吗?我的 array 是一个对象数组。
应该这样做,Joshua - 该对象是一个迭代器,一个具有 next() 方法的对象,每次调用它都会返回数组中的后续条目。里面没有(可见的)数据;您可以通过调用 next() 获取底层对象中的数据,这在幕后执行。抄送@tonyg
这也允许 await 按顺序工作,而 forEach 不能。
S
Sanjay Shr

这个怎么样

let numbers = [1,2,3,4,5]
numbers.forEach((number, index) => console.log(`${index}:${number}`))

其中 array.forEach 此方法有一个 index 参数,它是数组中正在处理的当前元素的索引。


选择的答案是在这个答案之前 6 年发布的,并且里面已经有同样的东西......
Foreach 不利于优化,因为 break 不可用。
佚名

小数组集合的解决方案:

for (var obj in arr) {
    var i = Object.keys(arr).indexOf(obj);
}

arr - ARRAY,obj - 当前元素的 KEY,i - COUNTER/INDEX

注意:方法keys()不适用于IE版本<9,你应该使用Polyfill代码。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys


我建议:改用计数器,循环增加它。
添加到 mayankcpdixit 后,请改用计数器,因为 indexOf 可能会对性能产生负面影响。
对象越大,这将变得越慢。这不成比例。
这是一种毫无意义的缓慢和复杂,因为 var i = 0;i++; 更短且更高效。此外,它不适用于不是自己的属性的可枚举属性。
@trusktr:如果需要……你仍然不应该使用它。更改集合时只需更改计数器。如果它不必就地,那就做一个很好的功能转换。
B
Bergi

For-in-loops 遍历对象的属性。不要将它们用于数组,即使它们有时会起作用。

对象属性没有索引,它们都是相等的,不需要按确定的顺序运行。如果您想计算属性,则必须设置额外的计数器(就像您在第一个示例中所做的那样)。

循环数组:

var a = [];
for (var i=0; i<a.length; i++) {
    i // is the index
    a[i] // is the item
}

循环对象:

var o = {};
for (var prop in o) {
    prop // is the property name
    o[prop] // is the property value - the item
}

永远不要像浪费资源那样做(var i=0; i<a.length; i++)。使用(var i=0, var len = a.length; i<len; i++)
@FelixSanz:浪费资源?没门。这是一个过早的微优化,几乎没有必要,var i=0; i<a.length; i++) 是标准循环模式,无论如何都被每个体面的 javascript 引擎优化。
@FelixSanz:是的,var i=0; i<a.length; i++ 是最佳做法。
KISS。如果您在真正需要它的地方编写循环,那么您要么做错了,要么您对它的必要性有比“最佳实践”更好的论据。是的,这是一种标准做法,但不适用于通用性能优化,而仅用于微优化。
KISS 适用于任何地方。 Premature optimisation 是一种反行为。
R
Robert Messerle

正如其他人所说,您不应该使用 for..in 来遍历数组。

for ( var i = 0, len = myArray.length; i < len; i++ ) { ... }

如果你想要更简洁的语法,你可以使用 forEach:

myArray.forEach( function ( val, i ) { ... } );

如果要使用此方法,请确保包含 ES5 shim 以添加对旧浏览器的支持。


R
Renish Gotecha

rushUp给出的答案是正确的,但这会更方便

for (let [index, val] of array.entries() || []) {
   // your code goes here    
}

|| [] 是不必要的,永远不会使用; array.entries() 总是真实的。
[index, val] 对我不起作用,它说“未定义”
你能分享你的阵列吗?
a
assayag.org

要在数组上使用 for..of 循环并检索索引,您可以使用 array1.indexOf(element) 它将返回循环中元素的索引值。您可以使用此方法返回索引和值。

array1 = ['a', 'b', 'c'] for (array1 的元素) { console.log(array1.indexOf(element), element) // 0 a 1 b 2 c }

正如评论中提到的,当数组包含非唯一值时,这将返回错误索引。 (考虑到 arr = ['a', 'b', 'c', 'a'],arr[3] 的索引将返回 0 而不是 3)


请稍微解释一下您的代码,而不是仅添加代码片段。另外,它并不能完全回答这个问题。这个问题是关于对象的,以数组为例可能会过于简单化。 (来自评论)
对可迭代对象很有用,感谢朋友,my_list.indexOf(element),尽管 lambda 表达式 forEach 非常有用。
这是不必要的二次方,并且当数组包含重复项时会产生不正确的结果。
R
Rivenfall

这是一个函数 eachWithIndex,它适用于任何可迭代的东西。

您还可以编写一个类似的函数 eachWithKey,使用 for...in 处理对象。

// example generator (returns an iterator that can only be iterated once)
function* eachFromTo(start, end) { for (let i = start; i <= end; i++) yield i }

// convers an iterable to an array (potential infinite loop)
function eachToArray(iterable) {
    const result = []
    for (const val of iterable) result.push(val)
    return result
}

// yields every value and index of an iterable (array, generator, ...)
function* eachWithIndex(iterable) {
    const shared = new Array(2)
    shared[1] = 0
    for (shared[0] of iterable) {
        yield shared
        shared[1]++
    }
}

console.log('iterate values and indexes from a generator')
for (const [val, i] of eachWithIndex(eachFromTo(10, 13))) console.log(val, i)

console.log('create an array')
const anArray = eachToArray(eachFromTo(10, 13))
console.log(anArray)

console.log('iterate values and indexes from an array')
for (const [val, i] of eachWithIndex(anArray)) console.log(val, i)

生成器的好处是它们很懒,可以将另一个生成器的结果作为参数。


s
sospedra

除了每个人都发布的非常好的答案之外,我想补充一点,最高效的解决方案是 ES6 entries。对于这里的许多开发人员来说,这似乎是矛盾的,所以我创建了 this perf benchamrk

https://i.stack.imgur.com/2WAkC.png

它快了约 6 倍。主要是因为不需要:a)多次访问数组,b)转换索引。


我不得不说你没有在上面的测试用例中比较苹果和苹果。在经典中,额外的 const v 被定义加上不必要的类型转换 Number(i) 都导致了它的开销。通过删除这些位,我的结果显示相反:经典快 4 倍。请检查更新版本 here
@Marshal 您的链接已失效
@javadba,那是因为 jsperf is down。我将创建一个新答案
说它是基于只包含另一种方法(也恰好是错误的)的基准的“最高效的解决方案”是非常误导的。如何将其与最佳答案进行比较?
a
akurtser

这是我的复合迭代器版本,它产生一个索引和任何传递的生成器函数的值,并带有一个(慢)素数搜索的例子:

const eachWithIndex = (iterable) => { return { *[Symbol.iterator]() { let i = 0 for(let val of iteratable) { i++ yield [i, val] } } } } const isPrime = (n) = > { for (i = 2; i < Math.floor(Math.sqrt(n) + 1); i++) { if (n % i == 0) { return false } } return true } let primes = { *[ Symbol.iterator]() { let Candidate = 2 while (true) { if (isPrime(candidate)) yield Candidate Candidate++ } } } for (const [i, prime] of eachWithIndex(primes)) { console.log(i,素数) if (i === 100) 中断 }


为什么你有一个函数 eachWithIndex[Symbol.iterator] 而不仅仅是一个函数 eachWithIndexeachWithIndex 不满足可迭代接口,这是 Symbol.iterator 的全部要点。
@Ry-很好,将 eachWithIndex 更改为接受可迭代并返回封闭的复合可迭代。
佚名

通过 js 中的 for of 循环系统,你可以找到所有索引为 no 的数组元素...

const menus = ['Bengali', 'Italiano', 'Americano', 'Thai', 'Chinese'];

for (const menus of menu.entries()) {
console.log(menus);
}

ReferenceError: menu is not defined