Mise en garde:
la question s'applique toujours aux boucles
for…of
.> N'utilisez pasfor…in
pour parcourir un Array , utilisez-le pour itérer. sur les propriétés d'un objet. Cela dit, cela
Je comprends que la syntaxe de base for…in
en JavaScript ressemble à ceci:
for (var obj in myArray) {
// ...
}
Mais comment puis-je obtenir la boucle counter/index?
var i = 0;
for (var obj in myArray) {
alert(i)
i++
}
for (var i = 0; 1 < myArray.length; i++) {
var obj = myArray[i]
alert(i)
}
Mais je préférerais utiliser la boucle for-in
plus simple. Je pense qu'ils ont l'air mieux et ont plus de sens.
Y a-t-il un moyen plus simple ou plus élégant?
for i, obj in enumerate(myArray):
print i
for…in
effectue une itération sur les noms de propriétés, et non sur les valeurs, et le fait dans un ordre non spécifié (oui, même après ES6). Vous ne devriez pas l'utiliser pour parcourir des tableaux. Pour eux, il existe une méthode forEach
dans ES5 qui transmet à la fois la valeur et l’index à la fonction que vous lui attribuez:
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
Ou de Array.prototype.entries
de ES6, qui prend désormais en charge les versions actuelles du navigateur:
for (const [i, value] of myArray.entries()) {
console.log('%d: %s', i, value);
}
Pour les iterables en général (où vous utiliseriez une boucle for…of
au lieu d'un for…in
), il n'y a rien d'intégré, cependant:
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);
}
Si vous vouliez réellement dire for…in
- énumération des propriétés - vous auriez besoin d'un compteur supplémentaire. Object.keys(obj).forEach
pourrait fonctionner, mais il ne comprend que les propriétés propres; for…in
inclut les propriétés énumérables n'importe où sur la chaîne de prototypes.
Dans ES6, il est bon d'utiliser for-of loop . Vous pouvez obtenir un index pour de of this
for (let [index, val] of array.entries()) {
// your code goes here
}
Notez que Array.entries()
renvoie un itérateur , ce qui lui permet de fonctionner dans la boucle for-of; ne confondez pas ceci avec Object.entries () , qui retourne un array de paires clé-valeur.
Des boucles répétitives parcourent les propriétés d'un objet. Ne les utilisez pas pour les tableaux, même s'ils fonctionnent parfois.
Les propriétés des objets n'ont alors aucun index, elles sont toutes égales et ne doivent pas nécessairement être exécutées dans un ordre déterminé. Si vous voulez compter les propriétés, vous devrez configurer le compteur supplémentaire (comme vous l'avez fait dans votre premier exemple).
boucle sur un tableau:
var a = [];
for (var i=0; i<a.length; i++) {
i // is the index
a[i] // is the item
}
boucle sur un objet:
var o = {};
for (var prop in o) {
prop // is the property name
o[prop] // is the property value - the item
}
Que dis-tu de ça
let numbers = [1,2,3,4,5]
numbers.forEach((number, index) => console.log(`${index}:${number}`))
Où array.forEach
cette méthode a un paramètre index
qui correspond à l'index de l'élément en cours de traitement dans le tableau.
Comme d'autres l'ont déjà dit, vous ne devriez pas utiliser for..in pour parcourir un tableau.
for ( var i = 0, len = myArray.length; i < len; i++ ) { ... }
Si vous voulez une syntaxe plus propre, vous pouvez utiliser forEach:
myArray.forEach( function ( val, i ) { ... } );
Si vous souhaitez utiliser cette méthode, veillez à inclure le module d'extension ES5 pour ajouter la prise en charge des navigateurs plus anciens.
Voici une fonction eachWithIndex
qui fonctionne avec tout ce qui est itérable.
Vous pouvez également écrire une fonction similaire eachWithKey
qui fonctionne avec des objets utilisant 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)
La bonne chose avec les générateurs est qu'ils sont paresseux et peuvent prendre comme argument le résultat d'un autre générateur.
C'est ma version d'un itérateur composite qui donne un index et la valeur de toute fonction génératrice passée avec un exemple de recherche principale (lente):
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, prime)
if (i === 100) break
}