Как перебрать объект JavaScript?

422

У меня есть объект в JavaScript:

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

Я хочу использовать forцикл, чтобы получить его свойства. И я хочу повторить это по частям (не все свойства объекта сразу).

С помощью простого массива я могу сделать это стандартным forциклом:

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

Но как это сделать с объектами?

nkuhta
источник
22
Имейте в виду, что свойства объекта хранятся не по порядку. Когда вы перебираете объект, нет гарантии, в каком порядке он появится.
Джеймс Аллардис

Ответы:

852

Для большинства объектов используйте for .. in:

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

С ES6, если вам нужны одновременно ключи и значения, выполните

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

Чтобы избежать регистрации унаследованных свойств, проверьте с помощью hasOwnProperty :

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

Вам не нужно проверять hasOwnPropertyпри итерации ключей, используете ли вы простой объект (например, тот, который вы сделали сами {}).

В этой документации MDN более подробно объясняется, как обращаться с объектами и их свойствами.

Если вы хотите сделать это «порциями», лучше всего извлечь ключи из массива. Поскольку заказ не гарантирован, это правильный путь. В современных браузерах вы можете использовать

let keys = Object.keys(yourobject);

Чтобы быть более совместимым, вам лучше сделать это:

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

Затем вы можете перебирать свои свойства по индексу yourobject[keys[i]]:

for (let i=300; i < keys.length && i < 600; i++) { 
   console.log(keys[i], yourobject[keys[i]]);
}
Денис Сегюре
источник
3
OP хочет выполнить это порциями, а не всеми ключами в одном цикле.
Павел
Да. Не полный объект в одном цикле.
Нкухта
2
@Cerbrus ОП уже знает, как перебирать массив по частям. Использование keysиз приведенного кода должно быть достаточно.
Йоши
2
@Cerbrus Пожалуйста, прочитайте, прежде чем комментировать! Что не ясно в «Чтобы быть более совместимым, вам лучше это сделать» ?
Денис Сегюре
2
@ am05mhz Как я уже сказал, это бесполезно с большинством объектов. Но не для всех. Попробуйте это: jsbin.com/hirivubuta/1/edit?js,console,output
Денис Сегюре
61

Вот еще одно итерационное решение для современных браузеров:

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

Или без функции фильтра:

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

Однако вы должны учитывать, что свойства в объекте JavaScript не отсортированы, т.е. не имеют порядка.

зрение
источник
Если я разорву цикл, он начнется с начала объекта в следующий раз, что не правильно.
Нкухта
21

С помощью Object.entriesвы делаете что-то вроде этого.

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

Метод Object.entries () возвращает массив собственного перечисляемого свойства данного объекта [ключ, значение]

Таким образом, вы можете перебирать объект и иметь keyи valueдля каждого объекта и получить что-то вроде этого.

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

или как это

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

Для справки взгляните на документы MDN для записей объектов

Адель Имран
источник
18

С новыми функциями ES6 / ES2015 вам больше не нужно использовать объект для перебора хеша. Вы можете использовать карту . Карты Javascript хранят ключи в порядке вставки, то есть вы можете перебирать их, не проверяя hasOwnProperty, что всегда было хаком.

Итерация по карте:

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"

или используйте forEach:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"
Павел
источник
1
ForEach является предпочтительным
Pungggi
14

Если вам нужен ключ и значение при итерации, вы можете использовать цикл for ... с 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

Единственный надежный способ сделать это - сохранить данные вашего объекта в 2 массива, один из ключей и один для данных:

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

Затем вы можете перебирать массивы, как обычно:

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

Я не использую Object.keys(obj), потому что это IE 9+.

Cerbrus
источник
3

-> если мы перебираем объект JavaScript, используя и находим ключ массива объектов

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

 console.log('key',key)

})
ashishdudhat
источник
1

Если вы хотите выполнить итерацию всего объекта сразу, вы можете использовать for inцикл:

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

Но если вы хотите разделить объект на части, вы не сможете. Там нет никакой гарантии, что свойства в объекте в любом указанном порядке. Поэтому я могу придумать два решения.

Первым из них является «удаление» уже прочитанных свойств:

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

Другое решение, которое я могу придумать, это использовать Array of Arrays вместо объекта:

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

Тогда стандартный forцикл будет работать.

Михал Мищин
источник
1

Я наконец-то придумал удобную служебную функцию с унифицированным интерфейсом для итерации объектов, строк, массивов, TypedArrays, карт, наборов (любых итерируемых элементов).

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

Вы можете попробовать использовать lodash. Современная библиотека утилит JavaScript, обеспечивающая модульность, производительность и дополнительные возможности для быстрой итерации объекта: -

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

Для итерации объекта мы обычно используем for..inцикл. Эта структура будет проходить по всем перечисляемым свойствам, включая те, которые наследуются через наследование прототипов. Например:

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

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

Тем не менее, он for..inбудет перебирать все перечисляемые элементы, и это не позволит нам разбить итерацию на куски. Для этого мы можем использовать встроенную Object.keys()функцию для извлечения всех ключей объекта в массиве. Затем мы можем разделить итерацию на несколько циклов for и получить доступ к свойствам с помощью массива ключей. Например:

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);
HovyTech
источник
1
Вообще-то, нет. Это означает, что Objects в порядке. Они не. If you can make sense of the sentence it workedработает только из-за деталей реализации. Это совсем не гарантировано. Также вы не должны TitleCase ваши функции и переменные. Это для classэс.
Флориан Вендельборн
0

На самом деле PITA это не является частью стандартного 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)
    })
}

Примечание. Я переключил параметры обратного вызова на (значение, ключ) и добавил третий объект, чтобы API соответствовал другим API.

Используйте это так

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});
Стивен Спунгин
источник
1
проголосовал только за ваше утверждение в первом предложении. Несмотря на то, что было бы лучше, если бы значение было первым параметром, вторым параметром индекса или ключа и третьим параметром объекта, чтобы оно больше походило на массив forEach (). Я бы порекомендовал хотя бы lodash.
контракте говорится, что я прав
Мне нравится идея порядка (значение, ключ). Вот как это делает библиотека типа Vue. Поскольку объект является контекстом, он действительно считает его первым параметром. Это довольно стандартно для функционального программирования.
Стивен Спунгин
Я бы согласился здесь, если бы не ECMA-262, определяющий массив как объект, имеющий forEach (), map (), redu (), filter (), которые все принимают обратные вызовы, получая порядок [значение, индекс, массив] , Объект в JS можно понимать как просто другую коллекцию; и затем эти методы объединяются в своих параметрах [value, key | index, context] (это то, что делают lodash и подчеркивание). На мой взгляд, этот протокол «единой коллекции» только сильнее. Кроме того, объект не является контекстом: thisдля обратного вызова вы можете установить любое значение, так как обратный вызов имеет свой собственный контекст.
контракте говорится, что я прав
Возможно, я должен был использовать рабочий приемник вместо этого. Во всяком случае все еще PITA; Я бы приветствовал параметры в любом порядке.
Стивен Спунгин
О, я вижу, что мы могли неправильно понять друг друга. Я всегда комментировал параметры обратного вызова и их порядок, а не реальную objectForEachфункцию. Извините, если это сбивает с толку.
контракте говорится, что я прав
0

Да. Вы можете перебрать объект, используя цикл for. Вот пример

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

ПРИМЕЧАНИЕ: приведенный выше пример будет работать только в IE9 +. Смотрите поддержку браузера Objec.keys здесь .

Омпракаш Арумугам
источник