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

1601

Как я могу перебрать все члены в объекте 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"
    }
}
По восточному времени
источник
11
возможный дубликат Loop через объект JavaScript
BuZZ-dEE

Ответы:

2115
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]);
    }
}
AgileJon
источник
13
Internet Explorer не соглашается ( вздыхает ), говорит «Объект не поддерживает это свойство или метод», когда вы делаете obj [prop]. Мне еще предстоит найти решение этой проблемы.
user999717
2
@MildFuzz на самом деле имеет смысл, если учесть, что у объектов JS нет необходимости иметь цифровые ключи. Вы не можете просто перебрать объект. JS for inочень похож на традиционный foreach.
Джейк Уилсон
4
for ... in - хорошее решение, но если вы используете обещания в цикле for () - будьте осторожны, потому что если вы создаете переменную в цикле, вы не сможете использовать ее в обещании 'then-function. Вы можете использовать переменную в цикле только один раз, поэтому она имеет в каждой функции-потом одно и то же, даже последнее значение. Если у вас есть эта проблема, попробуйте «Object.keys (obj) .forEach» или мой ответ ниже.
Бибер
hasOwnProperty почти всегда избыточен для современных браузеров (IE9 +).
Филюс
775

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

});

Аксель Раушмайер
источник
34
+1 для краткости кода, но, по-видимому, не так эффективен, как удивительно. JSPerf - для vs Object.keys
techiev2
6
Остерегайтесь этой ошибки, используя этот подход: «TypeError: Object.keys вызван не-объект». for ... in ... hasOwnPropertyМодель можно назвать на что - нибудь, насколько я могу сказать (объект, массив пустой, неопределенный, истина, ложь, номер примитивные, объекты).
theazureshadow
2
Обратите внимание, что IE7 не поддерживает это.
Пол Д. Уэйт
3
@ techiev2 эти тесты никогда не были действительными. Смотрите мои обновленные для текущего состояния производительности: jsperf.com/objdir/20
OrganicPanda
4
@ techiev2: это не то, Object.keys()что делает его медленным, это скорее forEach()повторный доступ к .length! Если forвместо этого вы используете классический -loop, он почти вдвое быстрее, чем for..in+ hasOwnProperty()в Firefox 33.
CodeManX
384

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

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]);
         }
      }
   }
}
Chango
источник
46
Короче: проверить hasOwnPropertyвнутри ваших for- inпетель.
Рори О'Кейн
59
Обратите внимание, что это необходимо, только если ваш объект имеет методы-прототипы. Например, если объект, через который вы проходите цикл, является просто объектом JSON, эта проверка вам не понадобится.
gitaarik
6
@rednaw Для безопасности я использую эту проверку, потому что Object.prototype может быть изменен. Никакой вменяемый скрипт не сделает этого, но вы не можете контролировать, какие скрипты могут запускаться на вашей странице безумными расширениями браузера. Расширения браузера запускаются на вашей странице (в большинстве браузеров), и они могут вызывать странные проблемы (например, установить для window.setTimeout значение null!).
Робокат
1
Большое спасибо
Синий трамвай
328

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

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 / 2016 вы можете использовать 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.entries(myObj).forEach(([key, val]) => console.log(key, val));

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.entries()сочетании с Object.fromEntries()( ES10 / 2019 ):

const loopNestedObj = obj =>
  Object.fromEntries(
    Object.entries(obj).map(([key, val]) => {
      if (val && typeof val === "object") [key, loopNestedObj(val)]; // recurse
      else [key, updateMyVal(val)]; // or do something with key and val.
    })
  );
Rotareti
источник
2
для вашего ES7, использующего пример Object.entries, вам нужно заключить параметры функции стрелки [key, val] в круглые скобки, например: `Object.entries (myObj) .forEach (([key, val]) => {/ * Statement * /}
puiu
6
Я думаю, что было бы полезно добавить тот факт, что Object.entries и Object.keys не выполняют итерацию по прототипу, что является большой разницей между ним и конструкцией for in.
Steviejay
Большое спасибо
Синий трамвай
95

Использование Underscore.js_.each :

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

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

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
}

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

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

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

And 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
     */
}

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

Approach подход ES7

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

}

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

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

And 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быстрее , чем родная forпетля, так что я бы рекомендовал использовать for...ofпри работе с Object.valuesв любом случае (4 - я и 6 - тестах).

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

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

vdegenne
источник
2
Пример ES7 работает как шарм с React Native!
Тай Бейли
Красиво объяснил. Спасибо
Алок Ранджан
30

Я знаю, что уже поздно, но мне понадобилось 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]);
            }

        }

    }

}
Azder
источник
1
Почему вы хранить hasOwnPropertyв ownsи затем вызвать owns.call(obj, prop)вместо того , чтобы просто вызов , obj.hasOwnProperty(prop)как этот ответ делает?
Рори О'Кейн
14
Потому objчто hasOwnPropertyфункция может быть определена сама по себе, поэтому она не будет использовать функцию from Object.prototype. Вы можете попробовать перед forциклом, подобным этому, obj.hasOwnProperty = function(){return false;}и он не будет перебирать любое свойство.
Azder
4
@Azder +1 за ответ и +1, если бы я мог за хорошую вещь о Object.prototype.hasOwnProperty. Я видел это ранее в исходном коде библиотеки подчеркивания, но не знаю почему.
Самуил
29
for(var k in validation_messages) {
    var o = validation_messages[k];
    do_something_with(o.your_name);
    do_something_else_with(o.your_msg);
}
хаос
источник
14

р значение

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

ИЛИ

Object.keys(p).forEach(key => { console.log(key, p[key]) })
Wesam
источник
9

В ES7 вы можете сделать:

for (const [key, value] of Object.entries(obj)) {
  //
}
Кевин Бертоммьер
источник
Я сделал несколько тестов, этот метод очень медленный при работе с большим количеством данных.
vdegenne
8
for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}
Дмитрий Фарков
источник
7

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

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);
Алиреза
источник
5

Вот улучшенная и рекурсивная версия решения AgileJon ( демо ):

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

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

JepZ
источник
5

Другой вариант:

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

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.

Дэниел Дьюхерст
источник
3

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

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

Сандип Байлкар
источник
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
user1833875
источник
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

Экзотический - глубокий траверс

JSON.stringify(validation_messages,(field,value)=>{
  if(!field) return value;

  // ... your code

  return value;
})

В этом решении мы используем заменитель, который позволяет глубоко пройти весь объект и вложенные объекты - на каждом уровне вы получите все поля и значения. Если вам нужно получить полный путь к каждому полю, посмотрите здесь

Камил Келчевски
источник
-6

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

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"]
user2515312
источник