Как мне перебрать или перечислить объект JavaScript?

2376

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

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

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

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

Показать ещё 2 комментария
Теги:
loops
each

35 ответов

3985
Лучший ответ

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

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

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

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}
  • 27
    Предполагается, что вы измените строку оповещения просто для ясности alert(key + " -> " + JSON.stringify(p[key]));
  • 69
    Можете ли вы объяснить необходимость hasOwnProperty? Что вы подразумеваете под прототипом?
Показать ещё 22 комментария
799

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

Оба Object.keys() и Object.entries() повторяют свойства в том же порядке, что и цикл for...in но игнорируют цепочку прототипов. Итерируемые свойства имеют только собственные свойства объекта.

  • 18
    Почему стандарт не предоставил Object.forEach(obj, function (value, key) {...}) ? :( Конечно, obj.forEach(function...) будет короче и дополнит Array.prototype.forEach , но это может привести к тому, что объекты определят свое собственное свойство forEach . Я предполагаю, что Object.keys защищает от обратного вызова, модифицирующего ключи объекта.
  • 6
    Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); }
Показать ещё 8 комментариев
314

Вы должны использовать для цикла

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

Поэтому при использовании 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
}
  • 30
    Это лучше, чем решение Левика, потому что оно позволяет основной логике быть только одним вложенным циклом вместо двух; делая для облегчения чтения кода. Хотя я бы потерял скобки вокруг продолжения; они лишние.
  • 50
    Я бы не стал удалять { } лично, потому что if без них делает немного неясным, что является частью, if а что нет. Но я думаю, что это просто вопрос мнения :)
Показать ещё 6 комментариев
239

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

В настоящее время многие известные библиотеки JavaScript предоставляют свои собственные методы для итерации над коллекциями, то есть над массивами, объектами и объектами, подобными массивам. Эти методы удобны в использовании и полностью совместимы с любым браузером.

  • Если вы работаете с jQuery, вы можете использовать метод jQuery.each(). Его можно использовать для беспрепятственной итерации по обоим объектам и массивам:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
    
  • В Underscore.js вы можете найти метод _.each(), который выполняет итерацию по списку элементов, каждый из которых приводит к поставленной функции (обратите внимание на порядок аргументов в функции iteratee!):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
    
  • 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 изменили параметры :)
46

В 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

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

UPD:

сравнение производительности для всех наиболее популярных случаев в этом вопросе на perfjs.info:

литеральная итерация объекта

  • 0
    Действительно, я просто хотел опубликовать этот метод. Но ты избил меня до этого :(
  • 0
    jsperf.com/object-iteration-comparison
38

Вы можете просто перебрать его, например:

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

Обратите внимание, что key не будет принимать значение свойства, это просто значение индекса.

  • 12
    Это повторяется и даже не совсем правильно. Вы должны иметь проверку hasOwnProperty, чтобы сделать эту работу правильно
  • 3
    Первоначально я отказался от этого на основе вышеупомянутого комментария, пока не понял, что этот ответ пришел первым, поэтому не «повторяется». Возможно, он неполон, но во многих случаях работает просто отлично.
27

Предисловие:

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

Здесь, в 2018 году, ваши возможности для прокрутки свойств объекта:

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

Со всеми из них, кроме " for-in, вы должны использовать какую-то петлевую конструкцию в массиве (for, for-of, forEach и т.д.).

Примеры:

for-in :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name in o) {
    const value = o[name];
    console.log('${name} = ${value}');
}

Object.keys (с циклом for-of loop, но вы можете использовать любую петлевую конструкцию):

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.keys(o)) {
    const value = o[name];
    console.log('${name} = ${value}');
}

Object.values :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const value of Object.values(o)) {
    console.log('${value}');
}

Object.entries :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const [name, value] of Object.entries(o)) {
    console.log('${name} = ${value}');
}

Object.getOwnPropertyNames :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertyNames(o)) {
    const value = o[name];
    console.log('${name} = ${value}');
}

Object.getOwnPropertySymbols :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertySymbols(o)) {
    const value = o[name];
    console.log('${String(name)} = ${value}');
}

Reflect.ownKeys :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Reflect.ownKeys(o)) {
    const value = o[name];
    console.log('${String(name)} = ${value}');
}

Все свойства, включая унаследованные неперечислимые:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from 'p'
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (let depth = 0, current = o; current; ++depth, current = Object.getPrototypeOf(current)) {
    for (const name of Reflect.ownKeys(current)) {
        const value = o[name];
        console.log('[${depth}] ${String(name)} = ${String(value)}');
    }
}
.as-console-wrapper {
  max-height: 100% !important;
}
25

Так как 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.

Надеюсь, это помогло кому-то.

EDIT:

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

  • 0
    Это выглядит совершенно излишним / ненужным для меня. Вы бы добавили его к каждому объекту в вашей системе? Я думал, что смысл предоставления итератора заключается в том, чтобы вы могли сделать `for (const [k, v] of myObject) '. Это просто выглядит как дополнительный код, обеспечивающий небольшое дополнительное значение.
19

через прототип с 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

После просмотра всех ответов здесь 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 .
  • 3
    Он может быть полностью Object.create(null) если создан с помощью Object.create(null)
16
for(key in p) {
  alert( p[key] );
}

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

  • 4
    При использовании такого цикла for key просто принимает значение индекса, так что он просто предупреждает 0, 1, 2 и т. Д. Вам необходимо получить доступ к p [key].
  • 1
    Это самый медленный метод итерации массива в JavaScript. Вы можете проверить это на своем компьютере - Лучший способ перебрать массивы в JavaScript
Показать ещё 3 комментария
15

Интересные люди в этих ответах затронули оба Object.keys() и for...of но никогда не комбинировали их:

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

Вы не можете просто for...of Object потому что это не итератор, а for...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
    Дело в точке . Пока люди прокручивают и находят это полезным, это все, что имеет значение. Обычно это я пытаюсь что-то сделать, мне не нравится то, что я вижу в Интернете, в конце концов, выясняю, а потом я возвращаюсь, чтобы поделиться. Это хороший документ, я на самом деле наткнулся на свои ответы, прежде чем поискать вещи, о которых я полностью забыл!
  • 0
    @HelpMeStackOverflowMyOnlyHope Лично мне не нравится модифицировать прототипы объектов, которые я не определял сам.
Показать ещё 5 комментариев
12

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 миллисекунды.
  • для... in/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);
});
  • 0
    если вы не хотите отпускать нотацию {}, вы все равно можете использовать of не создавая Map s
11

Вот еще один метод для итерации объекта.

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


Object.keys(p).forEach(key => { console.log(key, p[key]) })
  • 2
    Это довольно круто, однако для больших объектов метод for может быть более производительным.
10

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>
8

Метод Object.keys() возвращает массив заданных объектов для собственных перечислимых свойств. Подробнее об этом здесь

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

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))
  • 1
    Если у вас есть время, взгляните на это: meta.stackexchange.com/q/114762
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" -method:

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

Циклы могут быть довольно интересными при использовании чистого JavaScript. Похоже, что только ECMA6 (спецификация JavaScript для нового 2015 года) получил контроль над циклами. К сожалению, поскольку я пишу это, оба браузера и популярная интегрированная среда разработки (IDE) по-прежнему изо всех сил пытаются полностью поддержать новые колокола и свистки.

На первый взгляд, вот как выглядит цикл JavaScript 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

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

  • 0
    Не могли бы вы предоставить скрипку этой работы? Вот моя попытка. jsfiddle.net/abalter/sceeb211
  • 0
    @abalter Извините, я понял, что в моем коде есть опечатка. Я исправил это и обновил свой JsFiddle здесь: jsfiddle.net/sceeb211/2
Показать ещё 6 комментариев
5

Только код 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
}
4

Я сделал бы это вместо проверки 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");
}
3

В последнем сценарии ES вы можете сделать что-то вроде этого:

Object.entries(p);
3

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

Учитывая ES6, я хотел бы добавить свою собственную ложку сахара и предложить еще один подход к итерации по свойствам объекта.

Поскольку простой объект JS не является iterable просто из коробки, мы не можем использовать цикл 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 iterable на уровне prototype.

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

Кроме того, объекты, которые соответствуют итерабельному протоколу, могут использоваться с новой функцией ESa015 spread, поэтому мы можем читать значения свойств объекта как массив.

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

Или вы можете использовать destructuring назначение:

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

Вы можете проверить JSFiddle со всем приведенным выше кодом.

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

Если кому-то нужно выполнить цикл через 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");
      }
   }
}
3

Если вы хотите перебрать неперечислимые свойства, вы можете использовать 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) к свойствам в цикле или _.forIn(err) . Использование Object.getOwnPropertyNames(err) позволило мне получить доступ ко всем частям Error которые я не мог получить раньше. Спасибо!
2

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

let arrValues = Object.values( yourObject) ;

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

MDN DOCS Object.values()

и для ключей (allready answerd передо мной здесь)

let arrKeys   = Object.keys(yourObject);
  • 0
    Ответы требуют решения, которое возвращает ключи и значения.
  • 0
    Пеполе уже ответит за это. я добавлю это сейчас для вас
2

Объект становится итератором, когда он реализует метод .next()

const james = {
name: 'James',
height: `5'10"`,
weight: 185,

[Symbol.iterator]() {
let properties = []
for (let key of Object.keys(james)){
     properties.push(key);
 }

index = 0;
return {
        next: () => {
            let key = properties[index];
            let value = this[key];
            let done = index >= properties.length - 1 ;
            index++;
            return { key, value, done };
        }
    };
  }

};


const iterator = james[Symbol.iterator]();

console.log(iterator.next().value); // 'James'
console.log(iterator.next().value); // `5'10`
console.log(iterator.next().value); // 185
2

В 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.entries():

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

for (var i in Object.entries(p)){
	var key = Object.entries(p)[i][0];
	var value = Object.entries(p)[i][1];
	console.log('key['+i+']='+key+' '+'value['+i+']='+value);
}
  • 0
    пожалуйста, не удаляйте фрагмент, если вы редактируете мою запись
1

Если вы хотите перебирать только по свойствам, используйте один из приведенных выше ответов, однако, если вы хотите перебрать все, включая функции, то вы можете использовать Object.getOwnPropertyNames(OBJ)

for (let o of Object.getOwnPropertyNames(Math)) {
  console.log(o);
}

Я иногда использую это для быстрого тестирования всех функций на объектах с простыми входами и выходами.

  • 0
    Может ли downvoter, пожалуйста, уточнить?
0

Это как перебрать объект javascript и поместить данные в таблицу.

<body>
<script>
function createTable(objectArray, fields, fieldTitles) {
  let body = document.getElementsByTagName('body')[0];
  let tbl = document.createElement('table');
  let thead = document.createElement('thead');
  let thr = document.createElement('tr');

  for (p in objectArray[0]){
    let th = document.createElement('th');
    th.appendChild(document.createTextNode(p));
    thr.appendChild(th);
    
  }
 
  thead.appendChild(thr);
  tbl.appendChild(thead);

  let tbdy = document.createElement('tbody');
  let tr = document.createElement('tr');
  objectArray.forEach((object) => {
    let n = 0;
    let tr = document.createElement('tr');
    for (p in objectArray[0]){
      var td = document.createElement('td');
      td.appendChild(document.createTextNode(object[p]));
      tr.appendChild(td);
      n++;
    };
    tbdy.appendChild(tr);    
  });
  tbl.appendChild(tbdy);
  body.appendChild(tbl)
  return tbl;
}

createTable([
              {name: 'Banana', price: '3.04'}, // k[0]
              {name: 'Orange', price: '2.56'},  // k[1]
              {name: 'Apple', price: '1.45'}
           ])
</script>
0

У меня была аналогичная проблема при использовании Angular, вот решение, которое я нашел.

Шаг 1. Получить все ключи объектов. используя Object.keys. Этот метод возвращает массив заданных объектов собственных перечислимых свойств.

Шаг 2. Создайте пустой массив. Это место, где все свойства будут жить, так как ваш новый цикл ngFor будет указывать на этот массив, мы должны поймать их всех. Шаг 3.. Итерации бросают все ключи и нажимают каждый в массив, который вы создали. Вот как это выглядит в коде.

    // Evil response in a variable. Here are all my vehicles.
let evilResponse = { 
  "car" : 
    { 
       "color" : "red",
       "model" : "2013"
    },
   "motorcycle": 
    { 
       "color" : "red",
       "model" : "2016"
    },
   "bicycle": 
    { 
       "color" : "red",
       "model" : "2011"
    }
}
// Step 1. Get all the object keys.
let evilResponseProps = Object.keys(evilResponse);
// Step 2. Create an empty array.
let goodResponse = [];
// Step 3. Iterate throw all keys.
for (prop of evilResponseProps) { 
    goodResponse.push(evilResponseProps[prop]);
}

Вот ссылка на исходное сообщение. https://medium.com/@papaponmx/looping-over-object-properties-with-ngfor-in-angular-869cd7b2ddcc

-1
  • отступ одного уровня
  • одиночный набор скобок
  • максимальная совместимость с браузером
  • hasOwnProperty safe

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

for (var key in p) if (p.hasOwnProperty(key)) {
  var value = p[key];
  console.log(key, value);
}
-2

Так как ES2015 вы можете использовать for for, для прямого доступа к элементу:

// before ES2015
for(var key of elements){
  console.log(elements[key]);
}


// ES2015
for(let element of elements){
  console.log(element);
}

Надеюсь, это поможет кому-то.

  • 2
    Мало того, что это не помогает, это не точно. For ... of работает только если элементы определяют итератор. Это верно для массивов, наборов и карт, но не для объектов.
  • 0
    вы действительно можете сделать эту работу , @EvanCarroll
-5

Отказ от запроса ['конечная цель состоит в том, чтобы перебрать некоторые пары значений ключа'] и, наконец, не искать цикл.

var p ={"p1":"value1","p2":"value2","p3":"value3"};
if('p1' in p){
  var val=p['p1'];
  ...
}
  • 3
    Нет! Он написал «Теперь я хочу пройтись по всем элементам p», поэтому ему действительно нужен цикл, как в его принятом ответе.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню