Як ітерацію над об’єктом 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
Майте на увазі, що властивості об’єктів зберігаються не в порядку. Якщо ви повторюєте об'єкт, немає гарантії порядку, в якому вони з'являться.
Джеймс Еллардіс

Відповіді:


850

Для більшості об'єктів використовуйте 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
ОП хоче виконати це фрагментами, а не всі клавіші в одному циклі.
pawel

Так. Не повний об'єкт в одному циклі.
nkuhta

2
@Cerbrus OP вже знає, як ітератувати масив по частинах. Використання keysз наведеного коду повинно вистачити.
Йоші

2
@Cerbrus Будь ласка, прочитайте, перш ніж коментувати! Що не зрозуміло в "Щоб бути більш сумісним, вам краще зробити це" ?
Denys Séguret

2
@ am05mhz Як я вже говорив, з більшості об'єктів це марно. Але не для всіх. Спробуйте це: jsbin.com/hirivubuta/1/edit?js,console,output
Denys Séguret

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 не сортуються, тобто не мають порядку.


Якщо я перерву цикл, він розпочнеться з початку об'єкта наступного разу, це не правильно.
nkuhta

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 для записів об’єктів


17

З новими можливостями 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"

або використовувати дляEach:

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

Якщо ви хочете ключ і значення під час ітерації, ви можете використовувати цикл для ... з 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;
}

Іншим рішенням, про яке я можу придумати, є використання масиву масивів замість об'єкта:

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, яка забезпечує модульність, продуктивність та додаткові js для швидкого перегляду об’єктів: -

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()функцію для отримання всіх ключів об'єкта в масиві. Потім ми можемо розділити ітерацію на цикли для циклів і отримати доступ до властивостей за допомогою масиву ключів. Наприклад:

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 (). Я б рекомендував рекомендувати квартир.
ДОГОВІР каже, що я праворуч

Мені подобається ідея порядку (значення, ключ). Ось так це робить і така бібліотека, як Vue. Оскільки об'єкт - це контекст, він вважає, що він належить як перший параметр. Це досить стандартне функціональне програмування.
Стівен Спунгін

Я би погодився тут, якби не ECMA-262, що визначає масив як об'єкт, що має forEach (), map (), Reduct (), filter (), який приймає зворотні виклики, отримуючи замовлення [value, index, array] . Об'єкт в JS можна розуміти як просто іншу колекцію; а потім ці методи стають уніфікованими у своїх параметрах [значення, ключ | індекс, контекст] (саме це роблять лодаш та підкреслення). На мою думку, цей протокол "уніфікованої колекції" просто сильніший. Також об'єктом не є контекст: ви можете встановити thisвсе, що вам подобається, для зворотного дзвінка, оскільки зворотний виклик має власний контекст.
ДОГОВІР каже, що я праворуч

Можливо, я мав би використати робочий приймач замість цього. У будь-якому разі все ще PITA; Я б вітав параметри в будь-якому порядку.
Стівен Спунгін

О, я бачу, що ми могли б неправильно зрозуміти один одного. Я завжди коментував параметри зворотного виклику та їх порядок, а не фактичну objectForEachфункцію. Вибачте, якщо це було заплутано.
ДОГОВІР каже, що я праворуч

0

Так. Ви можете провести цикл через об'єкт, використовуючи для циклу. Ось приклад

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.