Как перебрать объект 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

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


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


3

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

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

 console.log('key',key)

})

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

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 здесь .


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.