Итерация по свойствам объекта


2040

var obj = {
    name: "Simon",
    age: "20",
    clothing: {
        style: "simple",
        hipster: false
    }
}

for(var propt in obj){
    console.log(propt + ': ' + obj[propt]);
}

Как переменная proptпредставляет свойства объекта? Это не встроенный метод или свойство. Почему он подходит к каждому свойству объекта?


11
if (typeof(obj[propt]) === 'object') {/ * Сделай это снова * /}
Нуб

13
Ну очень жаль за этот вопрос. Я знаю, что такое цикл, я не мог разобраться с «циклом через свойства объекта», который, я думаю, теперь очищен. Кроме того, они порекомендовали мне «JavaScript Step by Step 2nd Edition» - Стив Сюринг в школе.
Рафаи

242
Это хороший вопрос для начинающих. Я бы добавил, что у меня 15-летний профессиональный опыт работы с другими языками, и мне нужен был этот ответ. Я бы плюс 2000, если бы мог.
Натан Треш

60
Сумасшедший, но я заходил на эту страницу каждые несколько месяцев в течение многих лет, чтобы заново изучить синтаксис того, как это сделать. Я не удосужился вспомнить, как это сделать ... Я просто помню, что эта страница всегда здесь, на SO.
HDave

14
Это самая странная страница, которую я видел в StackOverflow. Если вы внимательно прочитаете вопрос, только один ответ даже начинает пытаться ответить на то, что на самом деле спрашивается, и у него оценка -6. Ответ с наивысшей оценкой, который был принят, не только не отвечает, но и просто ошибочен.

Ответы:


2426

Для перебора свойств требуется дополнительная hasOwnPropertyпроверка:

for (var prop in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        // do stuff
    }
}

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

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


Также возможно вызвать hasOwnPropertyчерез сам объект:

if (obj.hasOwnProperty(prop)) {
    // do stuff
}

Но это не удастся, если объект имеет несвязанное поле с тем же именем:

var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo');  // TypeError: hasOwnProperty is not a function

Вот почему Object.prototypeвместо этого безопаснее звонить :

var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo');  // true

21
@BT Согласно документации Mozilla : «Если вы хотите учитывать только свойства, связанные с самим объектом, а не с его прототипами, используйте getOwnPropertyNames или выполните проверку hasOwnProperty (также можно использовать propertyIsEnumerable)».
Давидмдем

3
Какой именно смысл звонить object.hasOwnProperty()? Разве тот факт, что propertyимеет какую-то ценность, не подразумевает, что это в object?
Алекс С

6
Потому что, Алекс S, прототип объекта содержит дополнительные свойства для объекта, которые технически являются частью объекта. Они унаследованы от базового класса объектов, но все еще являются свойствами. hasOwnProperty просто проверяет, является ли это свойство специфичным для этого класса, а не наследуемым от базового класса. Хорошее объяснение: brianflove.com/2013/09/05/javascripts-hasownproperty-method
Кайл Рихтер

87
Однако я чувствую, что должен упомянуть, что Object.keys (obj) теперь является гораздо лучшим решением для получения ключей самого объекта. Ссылка на документацию Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Кайл Рихтер

9
Одна важная часть информации отсутствует. propertyэто строка здесь, должна была быть вызвана propertyName. В противном случае может вызвать замешательство у JS новичков, как я, то есть, что делать внутри if.
Неолиск

1137

Начиная с JavaScript 1.8.5 вы можете использовать Object.keys(obj)массив свойств, определенных для самого объекта (те, которые возвращают true для obj.hasOwnProperty(key)).

Object.keys(obj).forEach(function(key,index) {
    // key: the name of the object key
    // index: the ordinal position of the key within the object 
});

Это лучше (и более читабельно), чем использование цикла for-in.

Поддерживается в следующих браузерах:

  • Firefox (Gecko): 4 (2,0)
  • Хром: 5
  • Internet Explorer: 9

Дополнительную информацию смотрите в справочнике по объекту Mozilla Developer Network Object.keys () .


7
Это теперь более широко поддерживается: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Дом Виньярд

3
И если вам нужна поддержка старых браузеров, вы можете использовать этот polyfill
KyleMit

27
В средах, которые поддерживают эту языковую конструкцию, этот метод позволяет вызывать Array.foreach: Object.keys(myObject).forEach(function(key,index) { //key = the name of the object key //index = the ordinal position of the key within the object });
Тодд Прайс

4
@ AJ_83 Нет хорошего способа вырваться из forEach (). Используйте some () в этом случае и верните true, чтобы сломать
Daniel Z.

11
почему это более читабельно, чем для? for candidate in candidateStatus... кажется читабельным для меня
Jona

309

Девочки и парни, мы находимся в 2019 году, и у нас не так много времени для набора текста ... Итак, давайте сделаем этот крутой новый модный ECMAScript 2016:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));

17
Чем это отличается от ответа Дэнни Р.?
крильгар

27
Это oneliner и использует карту вместо forEach. А также, возможно, для некоторых людей будет интересен консольный журнал.
Фрэнк Рот

Satly, это не работает, когда obj=window.performance.memory: - / Где, как for inделает. т.е.var obj = window.performance.memory; for( key in obj ) console.log( 'key=' + key + ' val=' + obj[key] );
Michaelangel007

2
window.performance.memoryподдерживается только Chrome и Object.keys(obj)возвращает пустой массив. Это не имеет ничего общего с .map.
Фрэнк Рот

На случай, если кто-то не захочет возиться с реструктуризацией этого однострочника, чтобы делать больше, чем одну вещь одновременно e, я разместил эту суть. По сути, он похож на большинство реализаций хэша и использует ( (key) => (value) )вместо него { key => value }, но если вам раньше не приходилось сталкиваться с этим, это могло бы помочь вам лучше его визуализировать: gist.github.com/the-nose-knows/9f06e745a56ff20519707433e28a4fa8
kayleeFrye_onDeck

216

Это for...in statement( спецификация MDN , ECMAScript ).

Вы можете прочитать его как « для каждого свойства IN на objобъект, присвоить каждое свойство к PROPT переменному , в своей очереди».


1
Спасибо большое, теперь я это понимаю. Я бился головой, просматривал книги и Google.
Рафаи

21
Согласен с @RightSaidFred, с inоператором и forзаявления не участвуют в общем, for-inзаявление представляет собой грамматическое по себе: for ( LeftHandSideExpression in Expression ),for ( var VariableDeclarationNoIn in Expression )
CMS

2
Странно, что этот ответ имеет так много голосов, тем более, что эти популярные комментарии, кажется, противоречат ему.
Дуг Молинью

9
Почему это помечено как ответ? Это, возможно, наименее полезный в этой теме ..
computrius

3
Наименее полезный ответ? Зависит от того, что вы думаете, спрашивал ОП; когда я впервые прочитал вопрос, это было похоже на озадаченное смущение по поводу механизма, с помощью которого переменная может использоваться для проверки свойств объекта, и который этот ответ красноречиво объясняет (несмотря на неправильное выражение «для в»). Я вижу, что вопрос «Почему он подходит к каждому свойству» может означать, что ОП искал hasOwnProperty, но не знает об этом, но я думаю, что, скорее всего, именно это хотел знать ОП и неправильно принял верное ответ на другой вопрос. :-)
ухабистый

157

В современных реализациях ES вы можете использовать Object.entries:

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

или

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

Если вы просто хотите перебрать значения, используйте Object.values:

for (const value of Object.values(obj)) { }

или

Object.values(obj).forEach(value => ...)

это было бы лучшим решением (object.entries ...), но я не могу его использовать. Если вы хотите сделать это несколько раз и не можете поддерживать его в своей среде, вы можете использовать полифилл на этой странице: developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…
Mario

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


27

Если ваша среда поддерживает ES2017, я бы порекомендовал Object.entries :

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

Как показано в документации Mozillas Object.entries () :

Метод Object.entries () возвращает массив пар собственных перечислимых свойств [ключ, значение] данного объекта в том же порядке, что и в цикле for ... in (отличие состоит в том, что цикл for-in перечисляет свойства в цепи прототипа).

В основном с Object.entries мы можем отказаться от следующего дополнительного шага, который требуется для старшего цикла for ... in :

// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}

22

JQuery позволяет вам сделать это сейчас:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});

1
$.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)})$ .each не подходит для объектов. Если объект имеет свойство длины и его значение равно нулю, весь объект обрабатывается так, как если бы он был пустым массивом.
Боб Стейн

Подробно, почему я думаю, что это подход к поиску ошибок .
Боб Стейн

21

Ответ Доминика идеален, я просто предпочитаю делать это так, чтобы было чище читать:

for (var property in object) {
    if (!object.hasOwnProperty(property)) continue;

    // Do stuff...
}

Должно быть в Objectверхнем регистре, хотя, нет?
Джонатан

18

Приведенные выше ответы немного раздражают, потому что они не объясняют, что вы делаете внутри цикла for после того, как убедитесь, что это объект: ВЫ НЕ ПОЛУЧАЕТЕ ЕГО ПРЯМО! На самом деле вы получили только КЛЮЧ, который вам нужен для подачи заявления в OBJ:

var obj = {
  a: "foo",
  b: "bar",
  c: "foobar"
};

// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
  // We check if this key exists in the obj
  if (obj.hasOwnProperty(someKey))
  {
    // someKey is only the KEY (string)! Use it to get the obj:
    var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"

    // NOW you can treat it like an obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

Это все ECMA5 безопасно. Даже работает в хромых версиях JS, таких как Rhino;)


15

Добавить использование ES2015 Reflect.ownKeys(obj)и перебирать свойства через итератор.

Например:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

может быть повторен

// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

Если вы хотите выполнять итерацию непосредственно по значениям ключей объекта, вы можете определить iterator, как итераторы JavaScipts по умолчанию для строк, массивов, типизированных массивов, Map и Set.

JS попытается выполнить итерацию через свойство итератора по умолчанию, которое должно быть определено как Symbol.iterator.

Если вы хотите иметь возможность перебирать все объекты, вы можете добавить его в качестве прототипа Object:

Object.prototype[Symbol.iterator] = function*() { 
    for(p of Reflect.ownKeys(this)){ yield this[p]; }
}

Это позволит вам перебирать значения объекта с помощью цикла for ..., например:

for(val of obj) { console.log('Value is:' + val ) }

Внимание : на момент написания этого ответа (июнь 2018 г.) все другие браузеры, кроме IE, поддерживают генераторы и for...ofитерацию черезSymbol.iterator


Хотя вы на самом деле не отвечаете на вопрос OP, это было очень полезно для меня, я еще не знал об Reflect.
Michiel

15
if(Object.keys(obj).length) {
    Object.keys(obj).forEach(key => {
        console.log("\n" + key + ": " + obj[key]);
    });
}

// *** Explanation line by line ***

// Explaining the bellow line
// It checks if obj has at least one property. Here is how:
// Object.keys(obj) will return an array with all keys in obj
// If there is no keys in obj, it will return empty array = []
// Then it will get it's length, if it has at least one element,
// it's bigger than 0 which evaluates to true and the bellow 
// code will be executed.
// Else means it's length = 0 which evaluates to false
// NOTE: you can use Object.hasOwnProperty() instead of Object.keys(obj).length
if(Object.keys(obj).length) {

    // Explaining the bellow line
    // Just like in the previous line, this returns an array with
    // all keys in obj (because if code execution got here, it means 
    // obj has keys.) 
    // Then just invoke built-in javascript forEach() to loop
    // over each key in returned array and calls a call back function 
    // on each array element (key), using ES6 arrow function (=>)
    // Or you can just use a normal function ((key) { blah blah }).
    Object.keys(obj).forEach(key => {

        // The bellow line prints out all keys with their 
        // respective value in obj.
        // key comes from the returned array in Object.keys(obj)
        // obj[key] returns the value of key in obj
        console.log("\n" + key + ": " + obj[key]);
    });
}

3
Здравствуйте, не могли бы вы добавить больше информации о вашем ответе, предоставляя только код не помогает.
Николас

Привет @ Николас Я добавил построчное объяснение в код. Дайте мне знать, если это все еще не ясно
Фуад Букредин

1
Поскольку forEach пропускаются пустые значения , я думаю, что вы можете избавиться от if и просто сделать Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));ответ Фрэнка Рота.
Darkproduct

12

Цикл for ... in представляет каждое свойство объекта, поскольку оно похоже на цикл for. Вы определили propt в цикле for ... in, выполнив:

    for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}

Цикл for ... in перебирает перечисляемые свойства объекта. Независимо от того, какую переменную вы определяете или помещаете в цикл for ... in, она изменяется каждый раз, когда переходит к следующему свойству, которое она выполняет. Переменная в цикле for ... in перебирает ключи, но ее значение является значением ключа. Например:

    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs "Simon"
    }

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

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


11
let obj = {"a": 3, "b": 2, "6": "a"}

Object.keys(obj).map((item) => {console.log("item", obj[item])})

// a
// 3
// 2

1
Как упоминалось в других комментариях, forEachздесь более уместно, так как mapон предназначен для возврата нового массива с результатами вызова блока кода на каждой итерации. Но нас интересуют только побочные эффекты каждой итерации, а не возвращаемое значение, поэтому нам не нужен тот новый массив, который mapнам дает.
Дэнни


10

Вы можете использовать Lodash. Документация

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});

10
С какой стати у этого «ответа» 10 голосов? Это полностью не в состоянии ответить на вопрос. Я начинаю терять веру в интеллект среднего разработчика JS.
developerbmw

1
@developerbmw Я понимаю, что использовать функции ES6 более правильно, но я ответил год назад. Пожалуйста, поделитесь своими мыслями, когда у вас будет минутка.
виктарпунько

1
Идея состоит в том, чтобы сосредоточиться больше на нативных методах, вместо того, чтобы предлагать пользователю добавить библиотеку 10000 строк на свою страницу. Не поймите меня неправильно, мне нравится использовать Lodash, но есть время и место для этого, и это не так.

9

Ваш forцикл перебирает все свойства объекта obj. proptопределяется в первой строке вашего цикла for. Это строка, которая является именем свойства objобъекта. В первой итерации цикла proptбудет «имя».


9

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

Вы должны думать о obj коллекции ключевых значений.


! с тем важным отличием, что эти «списки свойств» могут иметь имена в качестве ключей, в то время как обычные JS-массивы могут иметь только цифры в качестве ключей.
Qqwy

9

В настоящее время вы можете преобразовать стандартный объект JS в итерируемый объект, просто добавив метод Symbol.iterator. Затем вы можете использовать for ofцикл и получать его значения напрямую или даже использовать оператор распространения для объекта. Круто. Посмотрим, как мы можем это сделать:

var o = {a:1,b:2,c:3},
    a = [];
o[Symbol.iterator] = function*(){
                       var ok = Object.keys(this);
                            i = 0;
                       while (i < ok.length) yield this[ok[i++]];
                     };
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);


1
Интересный способ сделать это. Спасибо за function*открытие!
Бендж

5

Если работает Node, я бы порекомендовал:

Object.keys(obj).forEach((key, index) => {
    console.log(key);
});

5

Хотя самый лучший ответ верен, здесь есть альтернативный вариант использования, т.е. если вы перебираете объект и хотите в конце создать массив. Используйте .mapвместоforEach

const newObj = Object.keys(obj).map(el => {
    //ell will hold keys 
   // Getting the value of the keys should be as simple as obj[el]
})

4

Также добавляем рекурсивный способ:

function iterate(obj) {
    // watch for objects we've already iterated so we won't end in endless cycle
    // for cases like var foo = {}; foo.bar = foo; iterate(foo);
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  // check if we haven't iterated through the reference yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

Применение:

iterate({ foo: "foo", bar: { foo: "foo"} }); 

1
@faiz - см. мои комментарии, это защита от застрять в бесконечном цикле, когда вы периодически проходите через объект, который имеет циклические ссылки
Ондрей Свейдар

3

Цикл for..in состоит в том, что он создает новую переменную (var someVariable) и затем сохраняет каждое свойство данного объекта в этой новой переменной (someVariable) по одному. Поэтому, если вы используете block {}, вы можете выполнить итерацию. Рассмотрим следующий пример.

var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet

Это голосование, учитывая его простоту. В моем случае использования мне нужно проверить все атрибуты в объекте на наличие хитрых значений: NaN, null, undefined (это были точки на графике, и эти значения препятствовали рисованию графика). Чтобы получить значение вместо имени, в цикле вы бы просто сделали obj[someVariable]. Возможно, причина того, что за него так много проголосовали, заключается в том, что он не рекурсивный. Так что это не будет адекватным решением, если у вас высокоструктурированный объект.
Кэтрин Осборн

@KatharineOsborne или, возможно, потому, что следующая фраза немного загадочна: «Поэтому, если вы используете block {}, вы можете выполнять итерации». Код говорит больше, чем текст.
19

3

Здесь я перебираю каждый узел и создаю значимые имена узлов. Если вы заметили, instanceOf Array и instanceOf Object в основном делают одно и то же (хотя в моем приложении я даю другую логику)

function iterate(obj,parent_node) {
    parent_node = parent_node || '';
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            var node = parent_node + "/" + property;
            if(obj[property] instanceof Array) {
                //console.log('array: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            } else if(obj[property] instanceof Object){
                //console.log('Object: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            }
            else {
                console.log(node + ":" + obj[property]);
            }
        }
    }
}

примечание - меня вдохновляет ответ Ондрея Свейдара. Но это решение имеет лучшую производительность и менее неоднозначно


3

Вы в основном хотите пройтись по каждому свойству объекта.

JSFiddle

var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);

obj(prop)<- TypeError: obj не является функцией
le_m

@le_m мой плохой. Я должен случайно вынуть hasOwnPropertyатрибут. Это должно работать сейчас.
HovyTech

2

Я хочу добавить к ответам выше, потому что у вас могут быть другие намерения от Javascript. Объект JSON и объект Javascript - это разные вещи, и вы можете захотеть перебрать свойства объекта JSON, используя решения, предложенные выше, а затем удивиться.

Предположим, что у вас есть объект JSON, такой как:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

Неправильный способ перебора его «свойств»:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

Вы можете быть удивлены видеть протоколирование консоли 0, 1и т.д. , когда Перебор свойств prop1и prop2и prop3_1. Эти объекты являются последовательностями, а индексы последовательности являются свойствами этого объекта в Javascript.

Лучший способ рекурсивно перебрать свойства объекта JSON - это сначала проверить, является ли этот объект последовательностью или нет:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }

     }
}

1

Для дальнейшего уточнения принятого ответа стоит отметить, что если вы создадите экземпляр объекта с помощью var object = Object.create(null)затем object.hasOwnProperty(property), то вызовется ошибка TypeError. Поэтому, чтобы быть в безопасности, вам нужно вызвать его из прототипа так:

for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}

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