Jak iterować obiekt JavaScript?

422

Mam obiekt w JavaScript:

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

Chcę użyć forpętli, aby uzyskać jej właściwości. Chcę iterować go w częściach (nie we wszystkich właściwościach obiektu jednocześnie).

Za pomocą prostej tablicy mogę to zrobić za pomocą standardowej forpętli:

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

Ale jak to zrobić z przedmiotami?

nkuhta
źródło
22
Pamiętaj, że właściwości obiektów nie są przechowywane w kolejności. Podczas iteracji nad obiektem nie ma gwarancji kolejności, w jakiej się pojawią.
James Allardice

Odpowiedzi:

850

W przypadku większości obiektów użyj for .. in:

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

Z ES6, jeśli potrzebujesz zarówno kluczy, jak i wartości, zrób to

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

Aby uniknąć rejestrowania odziedziczonych właściwości, sprawdź za pomocą hasOwnProperty :

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

Nie musisz sprawdzać hasOwnPropertypodczas iteracji na klawiszach, jeśli używasz prostego obiektu (na przykład takiego, którym sam się stworzyłeś {}).

Ta dokumentacja MDN wyjaśnia bardziej ogólnie, jak postępować z obiektami i ich właściwościami.

Jeśli chcesz to zrobić „fragmentami”, najlepiej jest wyodrębnić klucze z tablicy. Ponieważ zamówienie nie jest gwarantowane, jest to właściwy sposób. W nowoczesnych przeglądarkach możesz używać

let keys = Object.keys(yourobject);

Aby być bardziej kompatybilnym, lepiej wykonaj następujące czynności:

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

Następnie możesz iterować po swoich właściwościach według indeksu yourobject[keys[i]]:

for (let i=300; i < keys.length && i < 600; i++) { 
   console.log(keys[i], yourobject[keys[i]]);
}
Denys Séguret
źródło
3
OP chce wykonać to w kawałkach, nie we wszystkich kluczach w jednej pętli.
pawel
Tak. Nie pełny obiekt w jednej pętli.
nkuhta
2
@Cerbrus OP już wie, jak iterować tablicę w częściach. Korzystanie keysz podanego kodu powinno wystarczyć.
Yoshi
2
@Cerbrus Proszę przeczytać przed komentowaniem! Co nie jest jasne w „Aby być bardziej kompatybilnym, lepiej to zrobić” ?
Denys Séguret,
2
@ am05mhz Jak powiedziałem, jest bezużyteczny dla większości obiektów. Ale nie dla wszystkich. Spróbuj tego: jsbin.com/hirivubuta/1/edit?js,console,output
Denys Séguret
61

Oto kolejne rozwiązanie iteracyjne dla nowoczesnych przeglądarek:

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

Lub bez funkcji filtrowania:

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

Należy jednak wziąć pod uwagę, że właściwości w obiekcie JavaScript nie są sortowane, tzn. Nie mają kolejności.

Wizja
źródło
Jeśli przerwę pętlę, zacznie się od początku obiektu następnym razem, to nie jest właściwy sposób.
nkuhta
21

Za pomocą Object.entriesciebie zrób coś takiego.

 // 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'] ]

Metoda Object.entries () zwraca tablicę własnej wyliczalnej właściwości danego obiektu [klucz, wartość]

Więc można iteracyjne nad obiekt i mieć keyi valuedla każdego obiektu i dostać coś takiego.

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.
});

lub tak

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

W celach informacyjnych zapoznaj się z dokumentacją MDN dotyczącą pozycji obiektów

Adeel Imran
źródło
17

Dzięki nowym funkcjom ES6 / ES2015 nie musisz już używać obiektu do iteracji po skrócie. Możesz użyć mapy . Mapy Javascript utrzymują klucze w kolejności wstawiania, co oznacza, że ​​możesz je powtarzać bez konieczności sprawdzania hasOwnProperty, co zawsze było naprawdę włamaniem.

Iteruj po mapie:

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"

lub użyj dla każdego:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"
Paweł
źródło
1
forEach jest preferowany
pungggi
14

Jeśli potrzebujesz klucza i wartości podczas iteracji, możesz użyć pętli for ... z 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
Derek Soike
źródło
7

Jedynym niezawodnym sposobem na to byłoby zapisanie danych obiektu w 2 tablicach, jednym z kluczy i jednym dla danych:

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.
    }
}

Następnie możesz iterować po tablicach, jak zwykle:

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]);
}

Nie używam Object.keys(obj), bo to IE 9+.

Cerbrus
źródło
3

-> jeśli iterujemy obiekt JavaScript za pomocą i znajdujemy klucz tablicy obiektów

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

 console.log('key',key)

})
ashishdudhat
źródło
1

Jeśli chcesz iterować cały obiekt naraz, możesz użyć for inpętli:

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

Ale jeśli chcesz podzielić obiekt na części, nie możesz tego zrobić. Nie ma gwarancji, że właściwości w obiekcie są w określonej kolejności. Dlatego mogę wymyślić dwa rozwiązania.

Pierwszym z nich jest „usunięcie” już odczytanych właściwości:

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

Innym rozwiązaniem, o którym mogę pomyśleć, jest użycie Array of Arrays zamiast obiektu:

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

Wtedy forbędzie działać standardowa pętla.

Michał Miszczyszyn
źródło
1

W końcu wymyśliłem przydatną funkcję narzędzia z ujednoliconym interfejsem do iterowania obiektów, ciągów, tablic, tablic typowych, map, zestawów (dowolnych Iterabeli).

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

Alrik Zachert
źródło
1

Możesz spróbować skorzystać z lodash - nowoczesnej biblioteki narzędzi JavaScript zapewniającej modułowość, wydajność i dodatki js w celu szybkiego iterowania obiektu: -

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>

Parth Raval
źródło
1

Do iteracji obiektów zwykle używamy for..inpętli. Ta struktura będzie przechodzić przez wszystkie policzalne właściwości, w tym te, które są dziedziczone poprzez dziedziczenie prototypowe. Na przykład:

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

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

Jednak for..inpętla nad wszystkimi elementami przeliczalnych i to nie będzie w stanie nas rozdzielić iteracji w kawałkach. Aby to osiągnąć, możemy użyć wbudowanej Object.keys()funkcji, aby pobrać wszystkie klucze obiektu w tablicy. Następnie możemy podzielić iterację na wiele pętli i uzyskać dostęp do właściwości za pomocą tablicy kluczy. Na przykład:

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]]);
}

Willem van der Veen
źródło
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);
HovyTech
źródło
1
Właściwie nie. Oznacza to, że Objects są w porządku. Oni nie są. If you can make sense of the sentence it workeddziała tylko ze względu na szczegóły implementacji. Nie ma gwarancji, że w ogóle będzie działać. Nie powinieneś także TitleCase swoich funkcji i zmiennych. To dla classes.
Florian Wendelborn,
0

Naprawdę PITA, to nie jest część standardowego Javascript.

/**
 * 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)
    })
}

Uwaga: zmieniłem parametry wywołania zwrotnego na (wartość, klucz) i dodałem trzeci obiekt, aby interfejs API był spójny z innymi interfejsami API.

Użyj tego w ten sposób

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});
Steven Spungin
źródło
1
głosowałem za wypowiedź w pierwszym zdaniu. Nawet jeśli byłoby lepiej, gdyby wartość była pierwszym parametrem, indeksem lub kluczem drugim parametrem, a obiektem trzecim parametrem, aby bardziej przypominała tablicę forEach (). Poleciłbym jednak lodash.
KONTRAKT MÓWI, ŻE JESTEM PRAWO
Podoba mi się idea kolejności (wartość, klucz). Tak właśnie robi biblioteka taka jak Vue. Ponieważ obiekt jest kontekstem, wydaje się, że należy on do pierwszego parametru. To dość standardowy program do programowania funkcjonalnego.
Steven Spungin
Zgodziłbym się tutaj, gdyby nie ECMA-262 definiujący tablicę jako obiekt posiadający forEach (), map (), redukcję (), filter (), które wszystkie odbierają wywołania zwrotne otrzymujące kolejność [wartość, indeks, tablica] . Obiekt w JS może być rozumiany jako kolejna kolekcja; a następnie metody te zostają ujednolicone w swoich parametrach [wartość, klucz | indeks, kontekst] (to właśnie robią lodash i podkreślenie). Moim zdaniem ten protokół „ujednoliconej kolekcji” jest po prostu silniejszy. Ponadto obiekt nie jest kontekstem: możesz ustawić thisdowolne dla wywołania zwrotnego, ponieważ wywołanie zwrotne ma swój własny kontekst.
KONTRAKT MÓWI, ŻE JESTEM PRAWO,
Być może powinienem był użyć odbiornika roboczego zamiast tego. W każdym razie nadal PITA; Mile widziane parametry w dowolnej kolejności.
Steven Spungin
Och, widzę, że mogliśmy się źle zrozumieć. Zawsze komentowałem parametry wywołania zwrotnego i ich kolejność, a nie faktyczną objectForEachfunkcję. Przepraszam, jeśli to było mylące.
KONTRAKT MÓWI, ŻE JESTEM PRAWO,
0

Tak. Możesz przechodzić przez obiekt za pomocą pętli for. Oto przykład

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]]);
}

UWAGA: powyższy przykład działa tylko w IE9 +. Zobacz obsługę przeglądarki Objec.keys tutaj .

Omprakash Arumugam
źródło
0
const o = {
  name: "Max",
  location: "London"
};

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

Wypróbuj online

Vishal
źródło