Как пройти через цикл или перечислить объект JavaScript?


2882

У меня есть объект JavaScript, как показано ниже:

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

Теперь я хочу , чтобы перебрать все pэлементы ( p1, p2, p3...) и получить ключи и значения. Как я могу это сделать?

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


9
Я изменил JSON на JavaScript (объект), чтобы избежать путаницы с объектными литералами и JSON.
Феликс Клинг

Ответы:


4372

Вы можете использовать for-inцикл, как показано другими. Однако вы также должны убедиться, что ключ, который вы получаете, является фактическим свойством объекта и не берется из прототипа.

Вот фрагмент:

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

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

Альтернатива for-of с 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, если оно не используется, оно вернет undefined для именованных свойств и 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? Что вы подразумеваете под прототипом?
Камачи

331
В javascript каждый объект имеет набор встроенных пар ключ-значение, которые имеют метаинформацию. Когда вы перебираете все пары ключ-значение для объекта, вы также перебираете их. hasOwnPropery () отфильтровывает их.
Даниэльтальский

57
На самом деле, для ... в не осуждается. Для каждого ... в том. Но мне действительно нравится термин археологи ... Я собираюсь начать использовать это.
Бен И

17
каждый объект в javascript (на самом деле пара ключ-значение) имеет свойство __proto__or 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(), который выполняет итерацию по списку элементов, передавая каждый из них поочередно предоставленной функции (обратите внимание на порядок аргументов в функции iteratee !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
  3. Lo-Dash предоставляет несколько методов для перебора свойств объекта. Basic _.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 (key, value) {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

Для старого браузера у вас есть простой и полный polyfill

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 ] - функция, предоставляющая массив имен собственных свойств объекта (даже не перечисляемых), чьи имена являются символами.
  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
Первоначально я отказался от этого на основе приведенного выше комментария, пока не понял, что этот ответ пришел первым, поэтому не «повторяется». Возможно, он неполон, но во многих случаях работает просто отлично.
Биллиноа

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]парам в объектах еще проще. Теперь известно, что он будет частью стандарта в соответствии с информацией о стадии ts39 .

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

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] of myObject) '. Это просто выглядит как дополнительный код, обеспечивающий небольшое дополнительное значение.
Дин Рэдклифф

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

Примечание: вы можете делать это над массивами, но вы также будете перебирать lengthи другие свойства.


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

1
Это самый медленный метод итерации массива в JavaScript. Вы можете проверить это на своем компьютере - Лучший способ перебрать массивы в JavaScript
Pencroff

5
@Pencroff: проблема в том, что вопрос не в том, чтобы перебирать массивы ...;)
Sk8erPeter

Это то, что я не понимаю в стеке потока. Ричард дал правильный ответ, и он был первым, кто дал этот ответ, но он не получил +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()


Вы можете сделать обычные объектные ассоциации итерацией! Вела себя так же, как Maps с непосредственным использованием модного 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 (не добавляя их всех), но все же хотели использовать аккуратную нотацию объектов, поскольку объекты теперь итерируемы, теперь вы можете просто создать 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
Дело в точке . Пока люди прокручивают вниз и находят это полезным, это все, что имеет значение. Обычно это я пытаюсь что-то сделать, мне не нравится то, что я вижу в Интернете, в итоге выясняю, а потом я возвращаюсь, чтобы поделиться. Это хороший документ, я на самом деле наткнулся на свои ответы, прежде чем поискать вещи, о которых я полностью забыл!
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): Array

извлекает все строковые ключи всех перечисляемых собственных (не наследуемых) свойств.

Таким образом, он дает тот же список ключей, что и вы, проверяя каждый ключ объекта с помощью 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(H) решение быстро на хром для маленьких и больших объектов
  • решения на основе явного индекса i (J, K), достаточно быстры во всех браузерах для небольших объектов (для Firefox также быстры для больших объектов, но средние в других браузерах)
  • решения, основанные на итераторах (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
});

Для тех людей, которые не любят метод " для ... в ":

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 2015) получила контроль над циклами. К сожалению, пока я пишу это, браузеры и популярная интегрированная среда разработки (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
Николя Бувретт

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

@abalter Это так. Убедитесь, что у вас Chrome версии 51 и вы включили флаг, как описано в моих комментариях к редактированию и Jsfiddle. Вы можете проверить детали здесь: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Николас Бувретт

Извините, что пропустил это по поводу флага. Я вижу, что это еще не полностью реализованная функция.
abalter

5

В ES6 у нас есть хорошо известные символы для представления некоторых ранее внутренних методов, вы можете использовать их для определения работы итераторов для этого объекта:

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

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

это даст тот же результат, что и использование for ... в цикле es6.

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

Но важно знать, какие возможности у вас сейчас есть, используя es6!


1
Пользовательский объектный итератор вызывает встроенный массив-итератор массива, который генерируется Object.keys()и выделяется в памяти ... Круто!
ооо

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]); } } }
Марек Бернад,

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 со всем кодом, который я предоставил выше.


Я обнаружил, что код будет генерировать значения, но без ключей. Можно ли повторять значения с ключами?
Пика

Да, ты можешь. Просто верните "yield [ключ, obj [ключ]];" из вашей функции генератора, а затем используйте его следующим образом "for (let [key, value] of {}) {}"
Артем Пранович

4

начиная с ES06, вы можете получить значения объекта в виде массива с

let arrValues = Object.values( yourObject) ;

он возвращает массив значений объекта и не извлекает значения из Prototype !!

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.