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


Как я могу перебирать все элементы в объекте 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"
    }
}

1217


источник


Ответы:


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

1778



В соответствии с 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]);

});


544



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

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

360



В 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.
      {});

132



С помощью Underscore.js _.each:

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});

91



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

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
}

*/

51



I know it's waaay late, but it did take me 2 minutes to write this optimized and improved version of AgileJon's answer:

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

        }

    }

}

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

26



for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}

8



This answer is an aggregate of the solutions that were provided in this post with some performance feedbacks. I think there is 2 use-cases and the OP didn't mention if he needs to access the keys in order use them during the loop process.

I. the keys need to be accessed,

the of and Object.keys approach

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

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

the in approach

let k;
for (k in obj) {

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

Use this one with cautious, as it could print prototype'd properties of obj

the ES7 approach

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

}

However, at the time of the edit I wouldn't recommend the ES7 method, because JavaScript initializes a lot of variables internally to build this procedure (see the feedbacks for proof). Unless you are not developing a huge app which deserves optimization, then it is ok but if optimization is your priority you should think about it.

II. we just need to access each values,

the of and Object.values approach

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

}

More feedbacks about the tests :

  • Caching Object.keys or Object.values performance is negligible

For instance,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • For Object.values case, using a native for loop with cached variables in Firefox seems to be a little faster than using a for...of loop. However the difference is not that important and Chrome is running for...of faster than native for loop, so I would recommend to use for...of when dealing with Object.values in any cases (4th and 6th tests).

  • In Firefox, the for...in loop is really slow, so when we want to cache the key during the iteration it is better to use Object.keys. Plus Chrome is running both structure at equal speed (1st and last tests).

You can check the tests here : https://jsperf.com/es7-and-misc-loops


8