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

1349

Как я могу перебирать все элементы в объекте JavaScript, включая значения, которые являются объектами.

Например, как я мог бы пройти через это (обращаясь к "your_name" и "your_message" для каждого)?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}
Теги:

22 ответа

1805
Лучший ответ
for (var key in validation_messages) {
    // skip loop if the property is from prototype
    if (!validation_messages.hasOwnProperty(key)) continue;

    var obj = validation_messages[key];
    for (var prop in obj) {
        // skip loop if the property is from prototype
        if(!obj.hasOwnProperty(prop)) continue;

        // your code
        alert(prop + " = " + obj[prop]);
    }
}
  • 12
    Internet Explorer не соглашается ( вздыхает ), говорит «Объект не поддерживает это свойство или метод», когда вы делаете obj [prop]. Мне еще предстоит найти решение этой проблемы.
  • 35
    Если вы используете jQuery, $ .each () / делает / работает в IE.
Показать ещё 2 комментария
645

В соответствии с ECMAScript 5 вы можете комбинировать Object.keys() и Array.prototype.forEach():

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

//
//	Visit non-inherited enumerable keys
//
Object.keys(obj).forEach(function(key) {

  console.log(key, obj[key]);

});
  • 19
    +1 для краткости кода, но, по-видимому, не так эффективен, как удивительно. JSPerf - для vs Object.keys
  • 6
    Остерегайтесь этой ошибки, используя этот подход: «TypeError: Object.keys вызван не-объект». Насколько я могу судить, шаблон for ... in ... hasOwnProperty можно вызывать для чего угодно (объект, массив, ноль, неопределенный, истина, ложь, числовой примитив, объекты).
Показать ещё 10 комментариев
389

Проблема с этим

for (var key in validation_messages) {
   var obj = validation_messages[key];
   for (var prop in obj) {
      alert(prop + " = " + obj[prop]);
   }
}

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

С помощью этого вы избежите этого:

for (var key in validation_messages) {
   if (validation_messages.hasOwnProperty(key)) {
      var obj = validation_messages[key];
      for (var prop in obj) {
         if (obj.hasOwnProperty(prop)) {
            alert(prop + " = " + obj[prop]);
         }
      }
   }
}
  • 44
    Короче: проверить hasOwnProperty внутри вашей for - in петлях.
  • 52
    Обратите внимание, что это необходимо, только если ваш объект имеет методы-прототипы. Например, если объект, который вы просматриваете, является просто объектом JSON, эта проверка вам не понадобится.
Показать ещё 1 комментарий
182

В ES6 вы можете пропустить такой объект: (используя функция стрелки)

Object.keys(myObj).forEach(key => {
    console.log(key);          // the name of the current key.
    console.log(myObj[key]);   // the value of the current key.
});

jsbin

В ES7 вы можете использовать Object.entries вместо Object.keys и прокручивать объект следующим образом:

Object.entries(myObj).forEach(([key, val]) => {
    console.log(key);          // the name of the current key.
    console.log(val);          // the value of the current key.
});

Вышеупомянутое также будет работать как однострочный:

Object.keys(myObj).forEach(key => console.log(key, myObj[key]));

jsbin

Если вы хотите также прокручивать вложенные объекты, вы можете использовать рекурсивную функцию (ES6):

const loopNestedObj = (obj) => {
  Object.keys(obj).forEach(key => {
    if (obj[key] && typeof obj[key] === 'object') loopNestedObj(obj[key]);  // recurse.
    else console.log(key, obj[key]);  // or do something with key and val.
  });
};

jsbin

То же, что и функция выше, но с ES7 Object.entries вместо Object.keys:

const loopNestedObj = (obj) => {
  Object.entries(obj).forEach(([key, val]) => {
    if (val && typeof val === 'object') loopNestedObj(val);  // recurse.
    else console.log(key, val);  // or do something with key and val.
  });
};

Если вы используете функциональное программирование, вы можете использовать Object.keys/Object.entries для перечисления объекта, затем обработать значения, а затем использовать reduce() для преобразования обратно в новый объект.

const loopNestedObj = (obj) => 
  Object.keys(obj)
    // Use .filter(), .map(), etc. if you need.
    .reduce((newObj, key) => 
      (obj[key] && typeof obj[key] === 'object') ?
        {...newObj, [key]: loopNestedObj(obj[key])} :  // recurse.
        {...newObj, [key]: obj[key]},                  // Define value.
      {});
  • 2
    для вашего ES7 с использованием примера Object.entries вам нужно заключить параметры функции стрелки [key, val] в круглые скобки, например: `Object.entries (myObj) .forEach (([key, val]) => {/ * Statement * /}
  • 5
    Я думаю, что было бы полезно добавить тот факт, что Object.entries и Object.keys не выполняют итерацию по прототипу, что является большой разницей между ним и конструкцией for in.
93

Используя Underscore.jss _.each:

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});
  • 3
    Спасибо, Тим, используя подчеркивание, поэтому определенно хорошо иметь быстрый и чистый вариант.
52

Если вы используете рекурсию, вы можете вернуть свойства объекта любой глубины -

function lookdeep(object){
    var collection= [], index= 0, next, item;
    for(item in object){
        if(object.hasOwnProperty(item)){
            next= object[item];
            if(typeof next== 'object' && next!= null){
                collection[index++]= item +
                ':{ '+ lookdeep(next).join(', ')+'}';
            }
            else collection[index++]= [item+':'+String(next)];
        }
    }
    return collection;
}

//example

var O={
    a:1, b:2, c:{
        c1:3, c2:4, c3:{
            t:true, f:false
        }
    },
    d:11
};
var lookdeepSample= 'O={'+ lookdeep(O).join(',\n')+'}';


/*  returned value: (String)
O={
    a:1, 
    b:2, 
    c:{
        c1:3, c2:4, c3:{
            t:true, f:false
        }
    },
    d:11
}

*/
  • 2
    Остерегайтесь циклов, например, вызывая их на узле DOM.
30

Этот ответ представляет собой совокупность решений, которые были предоставлены в этом сообщении, с некоторыми отзывами о производительности. Я думаю, что есть 2 варианта использования, и OP не упоминал, нужно ли ему обращаться к клавишам, чтобы использовать их во время цикла.

I. Ключи должны быть доступны,

of и Object.keys подхода

let k;
for (k of Object.keys(obj)) {

    /*        k : key
     *   obj[k] : value
     */
}

in подходе

let k;
for (k in obj) {

    /*        k : key
     *   obj[k] : value
     */
}

Используйте это с осторожностью, так как он может печатать прототипы свойств obj

подход ES7

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

}

Однако во время редактирования я бы не рекомендовал метод ES7, потому что JavaScript инициализирует много переменных внутри, чтобы построить эту процедуру (см. Обратную связь для доказательства). Если вы не разрабатываете огромное приложение, которое заслуживает оптимизации, тогда это нормально, но если оптимизация - ваш приоритет, вы должны подумать об этом.

II. нам просто нужно получить доступ к каждому значению,

of и Object.values подход

let v;
for (v of Object.values(obj)) {

}

Больше отзывов о тестах:

  • Кэширование Object.keys или Object.values незначительно

Например,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Для Object.values случае, используя родной for цикла с кэшированным переменными в Firefox, кажется, немного быстрее, чем при использовании for...of цикла. Однако разница не так важна, и Chrome работает for...of быстрее, чем native for цикла, поэтому я бы рекомендовал использовать for...of при работе с Object.values в любом случае (4-й и 6-й тесты).

  • В Firefox цикл for...in очень медленный, поэтому, когда мы хотим кэшировать ключ во время итерации, лучше использовать Object.keys. Кроме того, Chrome работает с одинаковой скоростью (1-й и последний тесты).

Вы можете проверить тесты здесь: https://jsperf.com/es7-and-misc-loops

  • 1
    Пример ES7 работает как шарм с React Native!
28

Я знаю это waaay поздно, но мне потребовалось 2 минуты, чтобы написать эту оптимизированную и улучшенную версию ответа AgileJon:

var key, obj, prop, owns = Object.prototype.hasOwnProperty;

for (key in validation_messages ) {

    if (owns.call(validation_messages, key)) {

        obj = validation_messages[key];

        for (prop in obj ) {

            // using obj.hasOwnProperty might cause you headache if there is
            // obj.hasOwnProperty = function(){return false;}
            // but owns will always work 
            if (owns.call(obj, prop)) {
                console.log(prop, "=", obj[prop]);
            }

        }

    }

}
  • 1
    Почему вы храните hasOwnProperty в owns а затем вызываете owns.call(obj, prop) вместо простого вызова obj.hasOwnProperty(prop) как этот ответ ?
  • 13
    Потому что для obj может быть hasOwnProperty функция hasOwnProperty поэтому он не будет использовать функцию из Object.prototype . Вы можете попробовать перед циклом for например, obj.hasOwnProperty = function(){return false;} и он не будет перебирать любое свойство.
Показать ещё 1 комментарий
27
for(var k in validation_messages) {
    var o = validation_messages[k];
    do_something_with(o.your_name);
    do_something_else_with(o.your_msg);
}
11

p - значение

for (var key in p) {
  alert(key + ' => ' + p[key]);
}

ИЛИ

Object.keys(p).forEach(key => { console.log(key, p[key]) })
8
for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}
6

В ES7 вы можете:

for (const [key, value] of Object.entries(obj)) {
  //
}
  • 0
    Я сделал несколько тестов, этот метод очень медленный при работе с большим количеством данных.
5

Здесь идет улучшенная и рекурсивная версия решения AgileJon (demo):

function loopThrough(obj){
  for(var key in obj){
    // skip loop if the property is from prototype
    if(!obj.hasOwnProperty(key)) continue;

    if(typeof obj[key] !== 'object'){
      //your code
      console.log(key+" = "+obj[key]);
    } else {
      loopThrough(obj[key]);
    }
  }
}
loopThrough(validation_messages);

Это решение работает для всех видов разной глубины.

4

Другая опция:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}
  • 0
    Я попробовал ваше решение в Chrome 55.0, и вы получили ошибку типа. Ваш ответ выглядит красиво и лаконично, если вы можете заставить его работать, это, вероятно, будет одним из лучших вариантов. Я пытался выяснить это, но не понимаю вашего решения.
  • 2
    @TolMera Исправлено.
3

ECMAScript-2017, только что завершившийся месяц назад, представляет Object.values ​​(). Теперь вы можете сделать это:

let v;
for (v of Object.values(validation_messages))
   console.log(v.your_name);   // jimmy billy
3

Мне кажется, стоит отметить, что jQuery отлично сортирует это с помощью $.each().

Смотрите: https://api.jquery.com/each/

Например:

$('.foo').each(function() {
    console.log($(this));
});

$(this) является единственным элементом внутри объекта. Примените $('.foo') к переменной, если вы не хотите использовать механизм селектора jQuery.

2

Я не мог получить вышеуказанные сообщения, чтобы делать то, что было после.

После игры с другими ответами я сделал это. Он взломан, но он работает!

Для этого объекта:

var myObj = {
    pageURL    : "BLAH",
    emailBox   : {model:"emailAddress", selector:"#emailAddress"},
    passwordBox: {model:"password"    , selector:"#password"}
};

... этот код:

// Get every value in the object into a separate array item ...
function buildArray(p_MainObj, p_Name) {
    var variableList = [];
    var thisVar = "";
    var thisYes = false;
    for (var key in p_MainObj) {
       thisVar = p_Name + "." + key;
       thisYes = false;
       if (p_MainObj.hasOwnProperty(key)) {
          var obj = p_MainObj[key];
          for (var prop in obj) {
            var myregex = /^[0-9]*$/;
            if (myregex.exec(prop) != prop) {
                thisYes = true;
                variableList.push({item:thisVar + "." + prop,value:obj[prop]});
            }
          }
          if ( ! thisYes )
            variableList.push({item:thisVar,value:obj});
       }
    }
    return variableList;
}

// Get the object items into a simple array ...
var objectItems = buildArray(myObj, "myObj");

// Now use them / test them etc... as you need to!
for (var x=0; x < objectItems.length; ++x) {
    console.log(objectItems[x].item + " = " + objectItems[x].value);
}

... производит это в консоли:

myObj.pageURL = BLAH
myObj.emailBox.model = emailAddress
myObj.emailBox.selector = #emailAddress
myObj.passwordBox.model = password
myObj.passwordBox.selector = #password
1

var obj={
name:"SanD",
age:"27"
}
Object.keys(obj).forEach((key)=>console.log(key,obj[key]));

Для циклического прохождения объекта JavaScript мы можем использовать forEach, а для оптимизации кода - функцию стрелки.

0

Несколько способов сделать это...

1) 2 слоя для... в петле...

for (let key in validation_messages) {
   const vmKeys = validation_messages[key];
   for (let vmKey in vmKeys) {
      console.log(vmKey + vmKeys[vmKey]);
   }
}

2) Использование Object.key

Object.keys(validation_messages).forEach(key => {
   const vmKeys = validation_messages[key];
   Object.keys(vmKeys).forEach(key => {
    console.log(vmKeys + vmKeys[key]);
   });
});

3) Рекурсивная функция

const recursiveObj = obj => {
  for(let key in obj){
    if(!obj.hasOwnProperty(key)) continue;

    if(typeof obj[key] !== 'object'){
      console.log(key + obj[key]);
    } else {
      recursiveObj(obj[key]);
    }
  }
}

И назовите это как:

recursiveObj(validation_messages);
0

Решение, которое работает для меня, заключается в следующем

_private.convertParams=function(params){
    var params= [];
    Object.keys(values).forEach(function(key) {
        params.push({"id":key,"option":"Igual","value":params[key].id})
    });
    return params;
}
0

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

https://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object

-5

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

var myObj = {
    rrr: undefined,
    pageURL    : "BLAH",
    emailBox   : {model:"emailAddress", selector:"#emailAddress"},
    passwordBox: {model:"password"    , selector:"#password"},
    proba: {odin:{dva:"rr",trr:"tyuuu"}, od:{ff:5,ppa:{ooo:{lll:'lll'}},tyt:'12345'}}
};


function lookdeep(obj,p_Name,gg){
    var A=[], tem, wrem=[], dd=gg?wrem:A;
    for(var p in obj){
        var y1=gg?'':p_Name, y1=y1 + '.' + p;
        if(obj.hasOwnProperty(p)){
           var tem=obj[p];
           if(tem && typeof tem=='object'){
               a1=arguments.callee(tem,p_Name,true);
               if(a1 && typeof a1=='object'){for(i in a1){dd.push(y1 + a1[i])};}
            }
            else{
               dd.push(y1 + ':' + String(tem));
            }
        }
    };
    return dd
};


var s=lookdeep(myObj,'myObj',false);
for (var x=0; x < s.length; ++x) {
console.log(s[x]+'\n');}

результат:

["myObj.rrr:undefined",
"myObj.pageURL:BLAH",
"myObj.emailBox.model:emailAddress",
"myObj.emailBox.selector:#emailAddress",
"myObj.passwordBox.model:password",
"myObj.passwordBox.selector:#password",
"myObj.proba.odin.dva:rr",
"myObj.proba.odin.trr:tyuuu",
"myObj.proba.od.ff:5",
"myObj.proba.od.ppa.ooo.lll:lll",
"myObj.proba.od.tyt:12345"]
  • 4
    \ (?_?)/ смущенный

Ещё вопросы

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