Come iterare su un oggetto JavaScript?


422

Ho un oggetto in JavaScript:

{
    abc: '...',
    bca: '...',
    zzz: '...',
    xxx: '...',
    ccc: '...',
    // ...
}

Voglio usare un forciclo per ottenere le sue proprietà. E voglio iterarlo in parti (non tutte le proprietà degli oggetti contemporaneamente).

Con un semplice array posso farlo con un forloop standard :

for (i = 0; i < 100; i++) { ... } // first part
for (i = 100; i < 300; i++) { ... } // second
for (i = 300; i < arr.length; i++) { ... } // last

Ma come farlo con gli oggetti?


22
Tenere presente che le proprietà degli oggetti non sono memorizzate in ordine. Quando si esegue l'iterazione su un oggetto non esiste alcuna garanzia per l'ordine in cui verranno visualizzati.
James Allardice,

Risposte:


851

Per la maggior parte degli oggetti, utilizzare for .. in:

for (let key in yourobject) {
  console.log(key, yourobject[key]);
}

Con ES6, se hai bisogno sia di chiavi che di valori contemporaneamente, fallo

for (let [key, value] of Object.entries(yourobject)) {
    console.log(key, value);
}

Per evitare la registrazione delle proprietà ereditate, verificare con hasOwnProperty :

for (let key in yourobject) {
   if (yourobject.hasOwnProperty(key)) {
      console.log(key, yourobject[key]);
   }
}

Non è necessario verificare hasOwnPropertydurante l'iterazione sui tasti se si utilizza un oggetto semplice (ad esempio uno con cui si è creato {}).

Questa documentazione MDN spiega più in generale come gestire gli oggetti e le loro proprietà.

Se vuoi farlo "in blocchi", la cosa migliore è estrarre le chiavi in ​​un array. Poiché l'ordine non è garantito, questo è il modo corretto. Nei browser moderni, è possibile utilizzare

let keys = Object.keys(yourobject);

Per essere più compatibile, è meglio farlo:

 let keys = [];
 for (let key in yourobject) {      
     if (yourobject.hasOwnProperty(key)) keys.push(key);
 }

Quindi puoi iterare sulle tue proprietà per indice yourobject[keys[i]]::

for (let i=300; i < keys.length && i < 600; i++) { 
   console.log(keys[i], yourobject[keys[i]]);
}

3
OP vuole eseguire questo in blocchi, non tutti i tasti in un singolo ciclo.
Pawel,

Sì. Oggetto non pieno in un ciclo.
nkuhta,

2
@Cerbrus L'OP sa già come eseguire l'iterazione di un array in parti. L'utilizzo keysdal codice fornito dovrebbe essere sufficiente.
Yoshi,

2
@Cerbrus Si prega di leggere prima di commentare! Cosa non è chiaro in "Per essere più compatibile, è meglio farlo" ?
Denys Séguret,

2
@ am05mhz Come ho detto, è inutile con la maggior parte degli oggetti. Ma non per tutti. Prova questo: jsbin.com/hirivubuta/1/edit?js,console,output
Denys Séguret

61

Ecco un'altra soluzione di iterazione per i browser moderni:

Object.keys(obj)
  .filter((k, i) => i >= 100 && i < 300)
  .forEach(k => console.log(obj[k]));

O senza la funzione filtro:

Object.keys(obj).forEach((k, i) => {
    if (i >= 100 && i < 300) {
        console.log(obj[k]);
    }
});

Tuttavia, è necessario considerare che le proprietà nell'oggetto JavaScript non sono ordinate, cioè non hanno alcun ordine.


Se interromperò il ciclo, inizierà la prossima volta dall'inizio dell'oggetto, non è il modo giusto.
nkuhta,

21

Usandoti Object.entriesfai qualcosa del genere.

 // array like object with random key ordering
 const anObj = { 100: 'a', 2: 'b', 7: 'c' };
 console.log(Object.entries(anObj)); // [ ['2', 'b'],['7', 'c'],['100', 'a'] ]

Il metodo Object.entries () restituisce un array della proprietà enumerabile di un determinato oggetto [chiave, valore]

Quindi puoi iterare sull'oggetto e avere keye valueper ciascuno degli oggetti e ottenere qualcosa del genere.

const anObj = { 100: 'a', 2: 'b', 7: 'c' };
Object.entries(anObj).map(obj => {
   const key   = obj[0];
   const value = obj[1];

   // do whatever you want with those values.
});

o così

// Or, using array extras
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

Per un riferimento, dai un'occhiata ai documenti MDN per le voci oggetto


18

Con le nuove funzionalità ES6 / ES2015, non è più necessario utilizzare un oggetto per scorrere su un hash. Puoi usare una mappa . Le mappe Javascript mantengono le chiavi in ​​ordine di inserimento, il che significa che puoi iterarle senza dover controllare hasOwnProperty, che è sempre stato un vero e proprio hack.

Scorrere su una mappa:

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

for (var key of myMap.keys()) {
  console.log(key);
}
// Will show 2 logs; first with "0" and second with "1"

for (var value of myMap.values()) {
  console.log(value);
}
// Will show 2 logs; first with "zero" and second with "one"

for (var [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

o utilizzare per ogni:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

1
Perché ciascuno è il preferito
pungggi,

14

Se si desidera la chiave e il valore durante l'iterazione, è possibile utilizzare un ciclo for ... of con Object.entries .

const myObj = {a: 1, b: 2}

for (let [key, value] of Object.entries(myObj)) {
    console.log(`key=${key} value=${value}`)
}

// output: 
// key=a value=1
// key=b value=2

7

L'unico modo affidabile per farlo sarebbe salvare i dati dei tuoi oggetti in 2 array, uno di chiavi e uno per i dati:

var keys = [];
var data = [];
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        keys.push(key);
        data.push(obj[key]); // Not necessary, but cleaner, in my opinion. See the example below.
    }
}

È quindi possibile scorrere le matrici come si farebbe normalmente:

for(var i = 0; i < 100; i++){
    console.log(keys[i], data[i]);
    //or
    console.log(keys[i], obj[keys[i]]); // harder to read, I think.
}
for(var i = 100; i < 300; i++){
    console.log(keys[i], data[i]);
}

Non sto usando Object.keys(obj), perché è IE 9+.


3

-> se eseguiamo l'iterazione su un oggetto JavaScript utilizzando e troviamo la chiave dell'array di oggetti

Object.keys(Array).forEach(key => {

 console.log('key',key)

})

1

Se desideri iterare l'intero oggetto in una volta, puoi utilizzare for inloop:

for (var i in obj) {
  ...
}

Ma se vuoi dividere l'oggetto in parti, infatti, non puoi. Non esiste alcuna garanzia che le proprietà dell'oggetto siano nell'ordine specificato. Pertanto, posso pensare a due soluzioni.

Il primo è quello di "rimuovere" le proprietà già lette:

var i = 0;
for (var key in obj) {
    console.log(obj[key]);
    delete obj[key];
    if ( ++i > 300) break;
}

Un'altra soluzione che mi viene in mente è quella di utilizzare Array of Arrays invece dell'oggetto:

var obj = [['key1', 'value1'], ['key2', 'value2']];

Quindi, il forciclo standard funzionerà.


1

Alla fine mi è venuta in mente una comoda funzione di utilità con un'interfaccia unificata per iterare oggetti, stringhe, matrici, array tipizzati, mappe, set (qualsiasi Iterable).

const iterate = require('@a-z/iterate-it');
const obj = { a: 1, b: 2, c: 3 };

iterate(obj, (value, key) => console.log(key, value)); 
// a 1
// b 2
// c 3

https://github.com/alrik/iterate-javascript


1

Puoi provare a utilizzare lodash- Una moderna libreria di utilità JavaScript che offre modularità, prestazioni ed extra per eseguire ripetutamente gli oggetti: -

var  users  =   {
    'fred':     { 
        'user':   'fred',
            'age':  40 
    },
    'pebbles':  { 
        'user':   'pebbles',
         'age':  1 
    }
}; 
_.mapValues(users,  function(o)  { 
    return  o.age; 
});
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
// The `_.property` iteratee shorthand.
console.log(_.mapValues(users,  'age')); // returns age property & value 
console.log(_.mapValues(users,  'user')); // returns user property & value 
console.log(_.mapValues(users)); // returns all objects 
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.js"></script>


1

Per l'iterazione degli oggetti usiamo solitamente un for..inciclo. Questa struttura passerà attraverso tutte le proprietà enumerabili , comprese quelle ereditate tramite ereditarietà prototipale. Per esempio:

let obj = {
  prop1: '1',
  prop2: '2'
}

for(let el in obj) {
  console.log(el);
  console.log(obj[el]);
}

Tuttavia, for..ineseguirà il ciclo su tutti gli elementi enumerabili e questo non ci consentirà di dividere l'iterazione in blocchi. Per ottenere ciò possiamo usare la Object.keys()funzione integrata per recuperare tutte le chiavi di un oggetto in un array. È quindi possibile suddividere l'iterazione in multipli per i loop e accedere alle proprietà utilizzando l'array keys. Per esempio:

let obj = {
  prop1: '1',
  prop2: '2',
  prop3: '3',
  prop4: '4',
};

const keys = Object.keys(obj);
console.log(keys);


for (let i = 0; i < 2; i++) {
  console.log(obj[keys[i]]);
}


for (let i = 2; i < 4; i++) {
  console.log(obj[keys[i]]);
}


0
var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);

1
In realtà no. Ciò implica che Objects sono in ordine. Loro non sono. If you can make sense of the sentence it workedfunziona solo a causa dei dettagli di implementazione. Non è garantito che funzioni affatto. Inoltre non dovresti TitleCase le tue funzioni e variabili. Questo è per classes.
Florian Wendelborn,

0

Davvero un PITA, questo non fa parte del Javascript standard.

/**
 * Iterates the keys and values of an object.  Object.keys is used to extract the keys.
 * @param object The object to iterate
 * @param fn (value,key)=>{}
 */
function objectForEach(object, fn) {
    Object.keys(object).forEach(key => {
        fn(object[key],key, object)
    })
}

Nota: ho impostato i parametri di callback su (valore, chiave) e ho aggiunto un terzo oggetto per rendere le API coerenti con le altre API.

Usalo in questo modo

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});

1
votato solo per la tua affermazione nella prima frase. Anche se sarebbe meglio se il valore fosse il primo parametro, l'indice o il secondo parametro chiave e il terzo parametro oggetto, per renderlo più simile all'array forEach (). Consiglierei comunque lodash.
IL CONTRATTO DICE CHE SONO GIUSTO il

Mi piace l'idea dell'ordine (valore, chiave). Ecco come funziona anche una libreria come Vue. Poiché l'oggetto è il contesto, pensa che appartenga al primo parametro. È piuttosto standard per la programmazione funzionale.
Steven Spungin,

Concordo qui, se non fosse per ECMA-262 che definisce un array come un oggetto con forEach (), map (), reduce (), filter (), che accettano tutti i callback che ricevono l'ordine [value, index, array] . Un oggetto in JS può essere inteso come solo un'altra raccolta; e poi questi metodi diventano unificati nei loro parametri di [valore, chiave | indice, contesto] (questo è ciò che stanno facendo lodash e trattino basso). A mio avviso, questo protocollo di "raccolta unificata" è solo più forte. Inoltre, l'oggetto non è il contesto: puoi impostare thisciò che desideri per il callback, poiché il callback ha il suo contesto.
IL CONTRATTO DICE CHE SONO GIUSTO

Forse avrei dovuto usare il ricevitore di lavoro invece di questo. Comunque ancora una PITA; Gradirei i parametri in qualsiasi ordine.
Steven Spungin,

Oh, vedo che potremmo esserci fraintesi. Ho sempre commentato i parametri di callback e il loro ordine, non la objectForEachfunzione reale . Scusami se era confuso.
IL CONTRATTO DICE CHE SONO GIUSTO il

0

Sì. È possibile eseguire il ciclo attraverso un oggetto utilizzando per ciclo. Ecco un esempio

var myObj = {
    abc: 'ABC',
    bca: 'BCA',
    zzz: 'ZZZ',
    xxx: 'XXX',
    ccc: 'CCC',
}

var k = Object.keys (myObj);
for (var i = 0; i < k.length; i++) {
    console.log (k[i] + ": " + myObj[k[i]]);
}

NOTA: l'esempio sopra menzionato funzionerà solo in IE9 +. Vedi il supporto del browser Objec.keys qui .


0
const o = {
  name: "Max",
  location: "London"
};

for (const [key, value] of Object.entries(o)) {
  console.log(`${key}: ${value}`);
}

Prova online

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.