Як я проходжу чи перераховую об’єкт JavaScript?


2877

У мене об’єкт JavaScript такий:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Тепер я хочу , щоб перебрати всі pелементи ( p1, p2, p3...) і отримати ключі і значення. Як я можу це зробити?

Я можу змінити об’єкт JavaScript, якщо це необхідно. Моя кінцева мета - переглядати деякі пари ключових значень, і, якщо можливо, я хочу уникати використання eval.


9
Я змінив JSON на JavaScript (об'єкт), щоб уникнути плутанини об'єктних літералів та JSON.
Фелікс Клінг

Відповіді:


4365

Ви можете використовувати for-inцикл, як показали інші. Однак ви також повинні переконатися, що ключ, який ви отримуєте, є фактичним властивістю об'єкта, а не походить від прототипу.

Ось фрагмент:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

Для альтернативи Object.keys () альтернатива:

var p = {
    0: "value1",
    "b": "value2",
    key: "value3"
};

for (var key of Object.keys(p)) {
    console.log(key + " -> " + p[key])
}

Зауважте, що використання for-ofзамість for-in, якщо не використовується, воно поверне невизначене для названих властивостей і Object.keys()забезпечує використання лише власних властивостей об'єкта без усіх властивостей ланцюга прототипу.

Використовуючи новий Object.entries()метод:

Примітка. Цей метод не підтримується в Internet Explorer. Ви можете розглянути можливість використання Polyfill для старих браузерів.

const p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

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

34
Запропонував би вам змінити лінію оповіщення лише для ясності наalert(key + " -> " + JSON.stringify(p[key]));
Стів Мідглі

80
Чи можете ви пояснити необхідність hasOwnProperty? Що ви маєте на увазі під прототипом?
kamaci

331
У JavaScript кожен об'єкт має купу вбудованих пар ключів-значень, які мають метаінформацію. Коли ви перебираєте всі пари ключових значень для об'єкта, ви також перебираєте їх. hasOwnPropery () фільтрує їх.
Даніелтальський

57
Насправді, бо ... в не застаріло. Для кожного ... в є. Але мені дуже подобається термін археологи ... Мені доведеться почати користуватися цим.
Ben Y

17
кожен об’єкт у javascript (насправді пара ключ-значення) має властивість, яку називають __proto__або prototype. У цьому властивості є посилання на його батьківський об'єкт. Об'єкт автоматично успадковує властивість від свого батьківського. Це причина використання hasOwnProperty, яка означає, що ми зацікавлені у власності об'єктів, а не в його батьківських.
Зубайр Алам

1104

Відповідно до ECMAScript 5, ви можете комбінувати Object.keys()та Array.prototype.forEach():

var obj = { first: "John", last: "Doe" };

Object.keys(obj).forEach(function(key) {
    console.log(key, obj[key]);
});

ECMAScript 6 додає for...of:

for (const key of Object.keys(obj)) {
    console.log(key, obj[key]);
}

ECMAScript 8 додає, Object.entries()що дозволяє уникнути пошуку кожного значення в оригінальному об'єкті:

Object.entries(obj).forEach(
    ([key, value]) => console.log(key, value)
);

Ви можете комбінувати for...of, руйнувати та Object.entries:

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

Обидва Object.keys()і Object.entries()повторюють властивості в тому ж порядку, що і for...inцикл, але ігнорують ланцюжок прототипу . Ітерація лише іменних властивостей об'єкта.


21
Чому стандарт не передбачав Object.forEach(obj, function (value, key) {...})? :( Звичайно, obj.forEach(function...)це буде коротше і доповнити Array.prototype.forEach, але це загрожує тим, що об'єкти визначать власну forEachвласність. Я припускаю, що Object.keysохоронці проти зворотного виклику змінюють клавіші об'єкта.
Девід Харкнес

7
Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); }
Девід Харкнес

7
@DavidHarkness У ES2017 є Object.entries. Там ви можете зробити наступне: Object.entries(obj).map/forEach(([key, value]) => console.log(key, value))([ключ, значення] - це руйнування масиву, щоб отримати доступ до обох елементів безпосередньо. І вам доведеться загортати параметри в додаткові паролі.)
Андреас Ліннерт

як мені отримати indexключ у json? Або якщо потрібно, я повинен використовувати окремий лічильник?
Сараванабалагі Рамачандран

3
for...ofстандарт ES6, а не ES2016.
Ракс Вебер

342

Ви повинні використовувати цикл for-in

Але будьте дуже обережні, використовуючи подібний цикл, тому що це буде циклічно всі властивості по прототипу ланцюга .

Тому під час використання циклів for-in завжди використовуйте hasOwnPropertyметод, щоб визначити, чи справді властивість в ітерації є властивістю об'єкта, на який ви перевіряєте:

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}

31
Це краще, ніж рішення Левіка, оскільки воно дозволяє основній логіці бути лише одним вкладеним циклом, а не двома; полегшення для читання коду. Хоча я б розпустив дужки навколо продовження; вони зайві.
SystemicPlural

52
Я б не видаляв { }особисто, тому що ifбез них робить трохи незрозумілим, що є частиною, ifа що ні. Але я думаю, це лише питання думки :)
pimvdb

34
Так, я вважаю за краще тримати { }головне, щоб уникнути плутанини, якщо згодом потрібно щось додати в ifобласть.
Андреас Греч

8
Читаючи попередній коментар, я зрозумів, що не використовував правильних термінів, бо сказав "якщо сфера"; але майте на увазі, що JavaScript має лише область функцій. Тож, що я насправді мав на увазі, було "якщо блокувати".
Андреас Греч

1
eomeroff, якщо вас це справді хвилює, ви завжди можете зробити щось на кшталт: Object.prototype.hasOwnProperty.call(p, prop) Однак це теж не може захистити від маніпуляцій на Object.prototype ...
jordancpaul

252

Питання не буде повним, якщо ми не згадаємо про альтернативні способи циклічного перегляду об’єктів.

На сьогоднішній день багато відомих бібліотек JavaScript надають власні методи ітерації над колекціями, тобто над масивами , об'єктами та об’єктами , схожими на масив . Ці методи зручні у використанні та повністю сумісні з будь-яким браузером.

  1. Якщо ви працюєте з jQuery , ви можете використовувати jQuery.each()метод. З його допомогою можна безперешкодно повторювати і об'єкти, і масиви:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
  2. У Underscore.js ви можете знайти метод _.each(), який повторює список елементів, поступаючи кожен по черзі на додану функцію (зверніть увагу на порядок аргументів у функції ітерації !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
  3. Lo-Dash пропонує кілька методів ітерації властивостей об'єкта. Базовий _.forEach()(або псевдонім _.each()) корисний для циклічного перегляду об’єктів і масивів, однак (!) Об'єкти з lengthвластивістю трактуються як масиви, і щоб уникнути такої поведінки, пропонується використовувати _.forIn()і _.forOwn()методи (для них також має бути valueаргумент).

    _.forIn(obj, function(value, key) {
        console.log(key, value);
    });

    _.forIn()ітераціює над власними та успадкованими переліченими властивостями об'єкта, тоді як _.forOwn()ітерація лише над власними властивостями об'єкта (в основному, перевірка hasOwnPropertyфункцій). Для простих об'єктів та літералів об'єктів будь-який із цих методів буде добре працювати.

Як правило, всі описані методи мають однакову поведінку з будь-якими об'єктами, що постачаються. Крім того, використання нативного for..inциклу, як правило, буде швидшим, ніж будь-яка абстракція, наприклад jQuery.each(), ці методи значно простіші у використанні, вимагають менше кодування та забезпечують кращу обробку помилок.


4
Щоб дійти до значення: $ .each (obj, function (ключ, значення) {console.log (value.title);});
Раві Рам

2
Просто смішно, як підкреслення та jquery змінили параметри :)
ppasler

52

У ECMAScript 5 у вас є новий підхід у ітераційних полях буквального - Object.keys

Більше інформації ви можете побачити на MDN

Мій вибір нижче - як більш швидке рішення в поточних версіях браузерів (Chrome30, IE10, FF25)

var keys = Object.keys(p),
    len = keys.length,
    i = 0,
    prop,
    value;
while (i < len) {
    prop = keys[i];
    value = p[prop];
    i += 1;
}

Ви можете порівняти ефективність цього підходу з різними реалізаціями на jsperf.com :

Підтримка веб-переглядача, яку ви можете побачити на таблиці компат Kangax

Для старого веб-переглядача у вас проста і повна заповнення

UPD:

порівняння ефективності для всіх найпопулярніших випадків цього питання на perfjs.info:

об'єктна буквальна ітерація


Дійсно, я просто хотів опублікувати цей метод. Але ти мене до цього побив :(
Джеймі Хатбер

50

Передмова:

  • Властивості об'єкта можуть бути власними (властивість на самому об'єкті) або успадкованими (не на самому об'єкті, на одному з його прототипів).
  • Властивості об'єкта можуть бути переліченими або нечислими . Не перелічувані властивості залишаються без переліку переліку / масивів властивостей.
  • Назви властивостей можуть бути рядками або символами. Властивості, назви яких є Символами, залишаються без переліку переліку / масивів властивостей.

Тут у 2018 році ваші варіанти перегляду певних властивостей об’єкта є (деякі приклади перелічено за списком):

  1. for-in[ MDN , spec ] - циклічна структура, яка проходить через назви перелічених властивостей об'єкта , включаючи успадковані, імена яких - рядки
  2. Object.keys[ MDN , spec ] - функція, що забезпечує масив імен власних , перелічених властивостей об'єкта , назви яких є рядками.
  3. Object.values[ MDN , специфікація ] - функція забезпечує масив значень об'єкта в власних , перелічуваних властивості.
  4. Object.entries[ MDN , spec ] - функція, що забезпечує масив імен та значень власних , перелічених властивостей об'єкта (кожен запис у масиві - це [name, value]масив).
  5. Object.getOwnPropertyNames[ MDN , spec ] - функція, що забезпечує масив імен власних властивостей об'єкта (навіть тих, що не перелічуються), імена яких - це рядки.
  6. Object.getOwnPropertySymbols[ MDN , spec ] - функція, що забезпечує масив імен власних властивостей об'єкта (навіть тих, що не перелічуються), імена яких є Symbols.
  7. Reflect.ownKeys[ MDN , spec ] - функція, що забезпечує масив імен власних властивостей об'єкта (навіть не перелічуваних), будь то ці назви рядків чи символів.
  8. Якщо ви хочете все з властивостей об'єкта, в тому числі не-перелічуваних успадкованих з них, вам потрібно використовувати цикл і Object.getPrototypeOf[ MDN , специфікація ] і використовувати Object.getOwnPropertyNames, Object.getOwnPropertySymbolsабо Reflect.ownKeysпо кожному об'єкту в ланцюжку прототипів (наприклад , в нижній частині цієї відповіді).

З усіма з них , за винятком for-in, ви б використовувати будь - то зациклення конструкцію на масив ( for, for-of, forEachі т.д.).

Приклади:

for-in:

Object.keys for-ofциклом, але ви можете використовувати будь-яку циклічну конструкцію) :

Object.values:

Object.entries:

Object.getOwnPropertyNames:

Object.getOwnPropertySymbols:

Reflect.ownKeys:

Усі властивості , включаючи успадковані безлічі:


Приємне доповнення перелічених властивостей об'єкта.
serraosays

49

Ви можете просто повторити його як:

for (var key in p) {
  alert(p[key]);
}

Зауважте, що keyвартість властивості не буде приймати, це лише значення індексу.


13
Це повторюється і навіть не зовсім коректно. Вам потрібно мати перевірку властивості hasOwnProperty, щоб зробити цю роботу належним чином
Vatsal

4
Я спочатку спростував це на підставі вищезазначеного коментаря, поки не зрозумів, що ця відповідь прийшов першим, тому не повторювався. Це, можливо, неповно, але працює дуже добре у багатьох випадках.
billynoah

27

Оскільки es2015 набуває все більшої популярності, я публікую цю відповідь, яка включає використання генератора та ітератора для плавної ітерації через [key, value]пари. Як це можливо в інших мовах, наприклад, Ruby.

Добре ось код:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Всю інформацію про те, як зробити ітератор та генератор, ви можете знайти на сторінці розробника Mozilla.

Сподіваюся, це комусь допомогло.

Редагувати:

ES2017 включить, Object.entriesщо [key, value]ще більше спростить ітерацію над парами в об'єктах. Зараз відомо, що це буде частиною стандарту відповідно до інформації про етап39 .

Я думаю, що настав час оновити свою відповідь, щоб вона стала ще більш свіжою, ніж зараз.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Докладніше про використання можна дізнатися на сторінці MDN


Це виглядає для мене абсолютно зайвим / непотрібним. Чи додали б ви це до кожного об'єкта у вашій системі? Я думав, що сенс надання ітератора полягає в тому, що ви можете зробити `for (const [k, v] myObject) '. Це просто виглядає як додатковий код, що забезпечує мало додаткових цінностей.
Дін Редкліфф

22
for(key in p) {
  alert( p[key] );
}

Примітка: ви можете робити це через масиви, але ви також повторите lengthі інші властивості.


4
Якщо ви користуєтеся циклом for для цього циклу, keyвін просто прийме значення індексу, так що воно просто сповістить 0, 1, 2 і т. Д. ... Вам потрібно отримати доступ до p [key].
Брайан

1
Це найповільніший метод ітерації масиву в JavaScript. Ви можете перевірити це на своєму комп’ютері - Найкращий спосіб ітерації масивів у JavaScript
Pencroff

5
@Pencroff: проблема полягає в тому, що мова не йде про
прокручування

Це те, що я не розумію в stackoverflow. Річард дав правильну відповідь, і він першим дав цю відповідь, але він не отримав жодної +1? @Bryan var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); }спливає "p1" та "p2" у сповіщеннях, так що в цьому неправильно ???
Себастьян

5
Я думаю, що головна відмінність полягає в якості: інші відповіді не тільки розповідають, як, але й розповідають про застереження (наприклад, прототип) і як поводитися з цими застереженнями. ІМХО, ті і інші відповіді є краще , ніж у мене :).
Річард Левассер

20

Переглянувши всі відповіді, подані тут, hasOwnProperty не потрібен для мого власного використання, оскільки мій об’єкт json чистий; насправді немає сенсу додавати будь-яку додаткову обробку JavaScript. Це все, що я використовую:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}

18
Чи чи об’єкт JSON чистий чи ні, не має значення. Якщо в будь-який інший час якийсь код встановлює властивість Object.prototype, він буде перерахований через for..in. Якщо ви впевнені, що не використовуєте жодної бібліотеки, яка робить це, то вам не потрібно дзвонити hasOwnProperty.
G-Wiz

4
Це може бути абсолютно чистим, якщо створено зObject.create(null)
Хуан Мендес

20

через прототип з forEach (), який повинен пропустити властивості ланцюга прототипу :

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3

2
Будьте обережні з прототипом: obj = { print: 1, each: 2, word: 3 }виробляє TypeError: number is not a function. Використання forEachдля узгодження подібної Arrayфункції може дещо зменшити ризик.
Девід Харкнес

18

Це цікаві люди в цих відповідях торкнулися як Object.keys()і for...ofале ніколи не поєднали їх:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

Ви не можете просто , тому що це не итератор, і чи ТРАЄКТОРІЇ некрасиво / неефективно. Я радий, що більшість людей утримуються від (з перевіркою або без неї ), оскільки це теж трохи безладно, тому, крім моєї відповіді вище, я хочу сказати ...for...ofObjectfor...index.forEach()Object.keys()
for...in.hasOwnProperty()


Ви можете зробити звичайні об'єктні об'єднання ітераційними! Поводиться так само, як Mapі з прямим використанням фантазійного for...of
DEMO, що працює в Chrome та FF (я припускаю, що лише ES6)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

До тих пір, поки ви включите мою підкладку нижче:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

Без створення справжнього об’єкта Map, який не має приємного синтаксичного цукру.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

Насправді, з цією мережею, якщо ви все-таки хотіли скористатись іншими функціональними можливостями Map (не переставляючи їх усіх), але все ж хотіли використати акуратні позначення об'єктів, оскільки об’єкти тепер доступні, тепер ви можете просто зробити з нього карту!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

Для тих, хто не любить скуйовджуватися або prototypeвзагалі возитися з ними , не соромтесь замість цього зробити функцію у вікні, називаючи її чимось на зразок getObjIterator()тоді;

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

Тепер ви можете просто називати це звичайною функцією, більше нічого не впливає

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

або

for (let pair of getObjIterator(ordinaryObject))

Немає причин, чому це не спрацювало б.

Ласкаво просимо в майбутнє.


1
Справа в точці . Поки люди прокручуються вниз і вважають це корисним, це все, що має значення. Зазвичай це я намагаюся зробити щось, не сподобавшись речі, які я бачу в Інтернеті, і в кінцевому підсумку з’ясую це, а потім повертаюся, щоб поділитися. Це добре doco, я насправді натрапив на власні відповіді перед тим, як гуляти речі, про які я зовсім забув!
Hashbrown

@HelpMeStackOverflowMyOnlyHope Особисто мені не подобається змінювати прототипи об'єктів, які я сам не визначав.
Янус Трольсен

@JanusTroelsen Ви навіть прочитали всю відповідь? For those who don't like to shim, or mess with prototype in general, feel free to make the function on window instead, calling it something like getObjIterator() then;
Hashbrown

Зауважте, що ця методика не працює на звичайних об'єктах, але все ж корисна.
noɥʇʎԀʎzɐɹƆ

це працює для простих об'єктів, це буквально вся суть (а також назви змінних, як ordinaryObjectнаголос, що магія все ще працює для цих типів). Ви перевіряли демонстрацію; що для вас не працює, @ noɥʇʎԀʎzɐɹƆ? (PS ваше зображення профілю SE - бос)
Hashbrown

13

Object.keys (obj): масив

витягує всі рядкові ключі всіх перелічених власних (не успадкованих) властивостей.

Таким чином, він дає той самий список ключів, що і ви маєте намір, протестуючи кожен об'єктний ключ з hasOwnProperty. Вам не потрібна додаткова тестова операція, ніж Object.keys( obj ).forEach(function( key ){})вона повинна бути швидшою. Доведемо це:

var uniqid = function(){
			var text = "",
					i = 0,
					possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			for( ; i < 32; i++ ) {
					text += possible.charAt( Math.floor( Math.random() * possible.length ) );
			}
			return text;
		}, 
		CYCLES = 100000,
		obj = {}, 
		p1,
		p2,
		p3,
		key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
	obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
	var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
	if ( obj.hasOwnProperty( key ) ) {
		var waste = obj[ key ];
	}
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

У своєму Firefox я маю такі результати

  • Підхід Object.keys зайняв 40,21101451665163 мілісекунд.
  • для ... в / hasOwnProperty підхід зайняв 98,26163508463651 мілісекунд.

PS. в Chrome різниця ще більша http://codepen.io/dsheiko/pen/JdrqXa

PS2: У ES6 (EcmaScript 2015) ви можете добре відібрати ітерабельний об'єкт:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});


якщо вам не здається відпускати позначення {}, ви все одно можете користуватися, of не створюючи Maps
Hashbrown

13

Ось ще один метод ітерації через об’єкт.

   var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};


Object.keys(p).forEach(key => { console.log(key, p[key]) })


3
Це досить круто, проте для великих об'єктів forметод може бути більш ефективним.
Рольф

13

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>


12

Ви також можете використовувати Object.keys () і перебирати клавіші об'єкта, як показано нижче, щоб отримати значення:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).forEach((key)=> {
 console.log(key +' -> '+ p[key]);
});


Ви заощадили мій час, дякую
Swap-IOS-Android


8

Тільки код JavaScript без залежностей:

var p = {"p1": "value1", "p2": "value2", "p3": "value3"};
keys = Object.keys(p);   // ["p1", "p2", "p3"]

for(i = 0; i < keys.length; i++){
  console.log(keys[i] + "=" + p[keys[i]]);   // p1=value1, p2=value2, p3=value3
}

8

Object.keys()Метод повертає масив власних перелічуваних властивостей заданого об'єкта. Детальніше про це читайте тут

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))


8

Продуктивність

Сьогодні 2020.03.06 я виконую тести вибраних рішень на Chrome v80.0, Safari v13.0.5 та Firefox 73.0.1 на MacOs High Sierra v10.13.6

Висновки

  • рішення, засновані на for-in(A, B), є швидкими (або найшвидшими) для всіх браузерів для великих та малих об'єктів
  • напрочуд for-of(Н) рішення швидко хромується для малих та великих предметів
  • рішення, засновані на явному індексі i(J, K), досить швидкі у всіх браузерах для невеликих об'єктів (для firefox також швидко для великих ojbects, але середньо швидко в інших браузерах)
  • рішення на основі ітераторів (D, E) є найповільнішими і не рекомендуються
  • рішення C повільне для великих об'єктів і середнє повільне для малих об'єктів

введіть тут опис зображення

Деталі

Тести на працездатність проводили для

  • невеликий об’єкт - з 3 полями - ви можете виконати тест на своїй машині ТУТ
  • 'великий' об'єкт - з 1000 полями - ви можете провести тест на своїй машині ТУТ

Нижче фрагменти представлені використані рішення

І ось результати для дрібних предметів на хромі

введіть тут опис зображення


7

Ви можете додати просту функцію forEach до всіх об'єктів, щоб ви могли автоматично переходити цикл через будь-який об’єкт:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        for (var key in this) {
            if (!this.hasOwnProperty(key)) {
                // skip loop if the property is from prototype
                continue;
            }
            var value = this[key];
            func(key, value);
        }
    },
    enumerable: false
});

Для тих людей, яким не подобається метод " for ... in ":

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        var arr = Object.keys(this);
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i];
            func(key, this[key]);
        }
    },
    enumerable: false
});

Тепер ви можете просто зателефонувати:

p.forEach (function(key, value){
    console.log ("Key: " + key);
    console.log ("Value: " + value);
});

Якщо ви не хочете конфліктувати з іншими методами forEach, ви можете назвати його своїм унікальним іменем.


3
Модифікація прототипів вбудованих об'єктів (подібних Object), як правило, вважається анти-шаблоном, оскільки це може легко викликати конфлікти з іншим кодом. Тому рани не рекомендую робити це таким чином.
Моріц

6

Цикли можуть бути досить цікавими при використанні чистого JavaScript. Схоже, що лише ECMA6 (Нова специфікація JavaScript JavaScript) отримала петлі під контролем. На жаль, поки я це пишу, і браузери, і популярне середовище інтегрованого розвитку (IDE) все ще намагаються повністю підтримати нові дзвіночки.

На перший погляд ось як виглядає цикл об’єктів JavaScript перед ECMA6:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

Крім того, я знаю, що це питання не входить в рамки цього питання, але в 2011 році ECMAScript 5.1 додав forEachметод лише для масивів, який в основному створив новий вдосконалений спосіб перебирати масиви, залишаючи при цьому непередавані об'єкти зі старим багатослівним і заплутаним forциклом. Але дивним є те, що цей новий forEachметод не підтримує, breakщо призводило до всіляких інших проблем.

В основному в 2011 році існує не справжній надійний спосіб зациклюватися на JavaScript, окрім того, що багато популярних бібліотек (jQuery, Underscore тощо) вирішили повторно реалізувати.

Станом на 2015 рік, тепер у нас є кращий спосіб переключити (і зламати) будь-який тип об'єкта (включаючи масиви та рядки). Ось як буде виглядати цикл у JavaScript, коли рекомендація стане основною:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

Зауважте, що більшість веб-переглядачів не підтримуватиме код, який було зазначено вище, станом на 18 червня 2016 року. Навіть у Chrome потрібно включити цей спеціальний прапор, щоб він працював: chrome://flags/#enable-javascript-harmony

Поки це не стане новим стандартом, старий метод все ще може бути використаний, але в популярних бібліотеках також є альтернативи або навіть легкі альтернативи для тих, хто не використовує жодної з цих бібліотек.


Чи можете ви надати загадку цього твору? Ось моя спроба. jsfiddle.net/abalter/sceeb211
abalter

@abalter Вибачте, я зрозумів, що маю друк в коді. Я виправив це та оновив ваш JsFiddle тут: jsfiddle.net/sceeb211/2
Nicolas Bouvrette

Я в хромі і отримую Uncaught TypeError: Object.entries is not a function. Це ще не реалізовано в хромі?
abalter

@abalter Це так. Переконайтеся, що у вас версія 51 Chrome і що ви включили прапор, як пояснено в моїй редакції та коментарях Jsfiddle. Ви можете перевірити деталі тут: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Nicolas Bouvrette

Вибачте, що я пропустив це щодо прапора. Я бачу, що це ще не повністю реалізована функція.
abalter

5

У ES6 у нас є відомі символи для викриття деяких раніше внутрішніх методів, ви можете використовувати їх для визначення того, як ітератори працюють на цей об’єкт:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

це дасть такий самий результат, як і для циклу es6.

for(var key in p) {
    console.log(key);
}

Але важливо знати можливості, які ви зараз маєте, використовуючи es6!


1
Спеціальний ітератор об'єктів викликає вбудований ітератор масиву масиву, який генерується Object.keys()та виділяється в пам'яті ... Класно!
ooo

5

Я б зробив це, а не перевіряв obj.hasOwnerPropertyвсередині for ... inциклу.

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}

5

    var p =[{"username":"ordermanageadmin","user_id":"2","resource_id":"Magento_Sales::actions"},
{"username":"ordermanageadmin_1","user_id":"3","resource_id":"Magento_Sales::actions"}]
for(var value in p) {
    for (var key in value) {
        if (p.hasOwnProperty(key)) {
            console.log(key + " -> " + p[key]);
        }
    }
}


json = [{"key1":"value1","key2":"value2"},{"key1":"value3","key2":"value4"}] for (var i = 0; i < json.length; i++) { for (var key in json[i]) { if (json[i].hasOwnProperty(key)) { console.log(key + " -> " + json[i][key]); } } }
Marek Bernád

5

Використання for-ofнаObject.keys()

Подібно до:

let object = {
   "key1": "value1"
   "key2": "value2"
   "key3": "value3"
};

for (var key of Object.keys(p)) {
   console.log(key + " : " + object[key])
}

4

Якщо ви також хочете переглядати неперелічені властивості , ви можете використовувати Object.getOwnPropertyNames(obj)для повернення масив усіх властивостей (перелічених чи ні), знайдених безпосередньо на даному об'єкті.

var obj = Object.create({}, {
  // non-enumerable property
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

obj.foo = 1; // enumerable property

Object.getOwnPropertyNames(obj).forEach(function (name) {
  document.write(name + ': ' + obj[name] + '<br/>');
});


2
Це фантастично, дякую за публікацію цієї відповіді. Мені потрібно було проаналізувати Errorоб'єкт, і я не зміг отримати властивості в циклі чи _.forIn(err)виклику. Використання Object.getOwnPropertyNames(err)дозволило мені отримати доступ до всіх частин того, до Errorчого я не міг потрапити раніше. Дякую!
Пірс

4

Якщо комусь потрібно провести цикл через arrayObjects з умовою :

var arrayObjects = [{"building":"A", "status":"good"},{"building":"B","status":"horrible"}];

for (var i=0; i< arrayObjects.length; i++) {
  console.log(arrayObjects[i]);
  
  for(key in arrayObjects[i]) {      
    
      if (key == "status" && arrayObjects[i][key] == "good") {
        
          console.log(key + "->" + arrayObjects[i][key]);
      }else{
          console.log("nothing found");
      }
   }
}


4

Враховуючи ES6, я хотів би додати власну ложку цукру та запропонувати ще один підхід до перегляду властивостей об'єкта.

Оскільки звичайний JS-об’єкт не доступний просто з вікна, ми не можемо використовувати for..ofцикл для повторення його вмісту. Але нас ніхто не може зупинити, щоб зробити це нестерпним .

Давайте маємо bookоб’єкт.

let book = {
  title: "Amazing book",
  author: "Me",
  pages: 3
}

book[Symbol.iterator] = function(){

  let properties = Object.keys(this); // returns an array with property names
  let counter = 0;
  let isDone = false;

  let next = () => {
    if(counter >= properties.length){
      isDone = true;
    }
    return { done: isDone, value: this[properties[counter++]] }
  }

  return { next };
}

Оскільки ми це зробили, ми можемо використовувати його таким чином:

for(let pValue of book){
  console.log(pValue);
}
------------------------
Amazing book
Me
3

Або якщо ви знаєте потужність генераторів ES6 , то ви, звичайно, можете зробити код вище набагато коротшим.

book[Symbol.iterator] = function *(){

  let properties = Object.keys(this);
  for (let p of properties){
    yield this[p];
  }

}

Звичайно, ви можете застосувати таку поведінку до всіх об'єктів, зробивши Objectітерабельним на prototypeрівні.

Object.prototype[Symbol.iterator] = function() {...}

Крім того, об'єкти, які відповідають протоколу ітерабельності, можна використовувати з новим оператором розповсюдження функцій ES2015, таким чином ми можемо читати значення властивостей об’єкта як масив.

let pValues = [...book];
console.log(pValues);
-------------------------
["Amazing book", "Me", 3]

Або ви можете скористатися завданням руйнування :

let [title, , pages] = book; // notice that we can just skip unnecessary values
console.log(title);
console.log(pages);
------------------
Amazing book
3

Ви можете перевірити JSFiddle з усім кодом, який я вказав вище.


Я виявив, що код генерує значення, але без ключів. Чи можна повторити значення за допомогою клавіш?
Піка

Так, ти можеш. Просто поверніть "return [key, obj [key]];" від вашої генераторної функції, а потім використовуйте її так: "для (нехай [ключ, значення] {}) {}"
Артем Пранович,

4

з ES06 ви можете отримати значення об'єкта як масив

let arrValues = Object.values( yourObject) ;

він повертає масив значень об'єкта і не витягує значення з прототипу !!

MDN DOCS Object.values ​​()

і для ключів (вже відповіді переді мною тут)

let arrKeys   = Object.keys(yourObject);

Відповіді запитують рішення, яке повертає і ключі, і значення.
Шон Ліндо

4

В останньому сценарії ES ви можете зробити щось подібне:

let p = {foo: "bar"};
for (let [key, value] of Object.entries(p)) {
  console.log(key, value);
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.