Üyeleri olarak nesnelerle düz bir JavaScript nesnesi arasında nasıl döngü yapılır?


1599

Nesneler olan değerler de dahil olmak üzere bir JavaScript nesnesindeki tüm üyeler arasında nasıl döngü oluşturabilirim.

Örneğin, bunun üzerinden nasıl geçebilirim (her biri için "adınız" ve "mesajınız" na erişerek)?

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

Yanıtlar:


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

13
Nesne [prop] yaptığınızda, Internet Explorer kabul etmiyor ( iç çekiyor ), "Nesne bu özelliği veya yöntemi desteklemiyor" diyor. Buna henüz bir çözüm bulamadım.
user999717

2
@MildFuzz aslında JS nesnelerinin sayısal tuşlara sahip olmadığını düşünüyorsanız mantıklı. Sadece bir nesneyi tekrarlayamazsınız. JS for ingeleneksel bir çok benzer foreach.
Jake Wilson

4
for ... in iyi bir çözümdür, ancak for () - döngüsünde vaatler kullanırsanız dikkatli olun, çünkü döngüde bir değişken oluşturursanız, sözde 'then-function' sözünü kullanamazsınız. Döngüde var sadece bir kez var, bu yüzden her sonra fonksiyonunda aynı, hatta son değer var. Bu sorunla karşılaşırsanız, "Object.keys (obj) .forEach" veya aşağıdaki cevabımı deneyin.
Biber

775

ECMAScript'e 5 altında, birleştirebilir Object.keys()ve 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
Kod kısalığı için +1, ancak görünüşe göre, şaşırtıcı bir şekilde kadar verimli performans göstermiyor. JSPerf - for in Object.keys
techiev2

6
Şu yaklaşımı kullanarak bu hataya dikkat edin: "TypeError: Nesne dışı olarak adlandırılan Object.keys". for ... in ... hasOwnPropertyKalıbını (nesne, dizi null, tanımsız, doğru, yanlış, sayı ilkel, nesneler) söyleyebilir kadarıyla, bir şey üzerinde çağrılabilir.
theazureshadow

2
IE7'nin bunu desteklemediğini unutmayın.
Paul D.Waite

3
@ techiev2 bu testler hiçbir zaman geçerli değildi. Mevcut performans durumu için güncellenmiş olanlarımı görün: jsperf.com/objdir/20
OrganicPanda

4
@ techiev2: Object.keys()yavaşlatan bir şey değil, daha çok forEach()ve tekrarlanan erişim .length! forBunun yerine klasik bir döngü kullanırsanız, Firefox 33'te for..in+ 'dan neredeyse iki kat daha hızlıdır.hasOwnProperty()
CodeManX

384

Bununla ilgili sorun

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

aynı zamanda ilkel nesnenin prototipini de incelemenizdir.

Bununla bir kaçınacak:

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

46
Kısaca: kontrol hasOwnPropertyİçerideki for- indöngüler.
Rory O'Kane

59
Bunun yalnızca nesnenizin prototip yöntemleri varsa gerekli olduğunu unutmayın. Örneğin, üzerinden geçtiğiniz nesne yalnızca bir JSON nesnesiyse, bu denetime ihtiyacınız yoktur.
gitaarik

6
@rednaw Güvenli olmak için bu denetimi Object.prototype değiştirilebildiğinden kullanıyorum. Hiçbir aklı başında komut dosyası bunu yapmaz, ancak çılgın tarayıcı uzantıları tarafından sayfanızda hangi komut dosyalarının çalıştırılabileceğini kontrol edemezsiniz. Tarayıcı uzantıları sayfanızda çalışır (çoğu tarayıcıda) ve garip sorunlara neden olabilir (örn. Window.setTimeout'u null olarak ayarlayın!).
robocat

1
Çok teşekkür ederim
Blue Tram

328

Gelen ES6 / 2015 böyle bir nesne döngü edilebilir: (kullanarak ok fonksiyonu )

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

In ES7 / 2016 kullanabilirsiniz Object.entriesyerine Object.keysböyle bir nesnenin içinden ve loop:

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

Yukarıdakiler aynı zamanda tek astar olarak da çalışacaktır :

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

jsbin

İç içe nesneler arasında da döngü oluşturmak istiyorsanız, özyinelemeli bir işlev (ES6) kullanabilirsiniz:

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

Yukarıdaki işlevle aynı, ancak ES7 ile Object.entries() yerine 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.
  });
};

Tek kullanarak gitmek içinde Burada iç içe nesneleri değişim değerlerinin döngü ve yeni bir nesne döndürür Object.entries()ile kombine Object.fromEntries()( / 2019 ES10 ):

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

2
Object.entries örneğini kullanarak ES7'niz için, ok işlevi parametrelerini [key, val] şu parantezlere sarmanız gerekir: `Object.entries (myObj) .forEach (([[key, val]) => {/ * ifadeleri * /}
puiu

6
Object.entries ve Object.keys'in, yapıdaki for ile arasındaki büyük fark olan prototip üzerinde yineleme yapmadığı gerçeğini eklemenin yararlı olacağını düşünüyorum.
steviejay

Çok teşekkür ederim
Blue Tram

95

Underscore.js_.each kullanarak :

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

4
Teşekkürler Tim, hızlı ve temiz bir seçenek olması kesinlikle alt çizgi kullanarak iyi.
Kodlayıcı

56

Özyineleme kullanıyorsanız, herhangi bir derinlikte nesne özelliklerini döndürebilirsiniz.

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
Bunu bir DOM düğümünde çağırmak gibi döngülere dikkat edin.
theazureshadow

45

Bu yanıt, bu yayında bazı performans geri bildirimleriyle sağlanan çözümlerin toplamıdır . Bence 2 kullanım vakası var ve OP döngü işlemi sırasında bunları kullanmak için anahtarlara erişmesi gerekip gerekmediğinden bahsetmedi.

I. anahtarlara erişilmesi gerekiyor,

And ofve Object.keysyaklaşımı

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

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

inyaklaşım

let k;
for (k in obj) {

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

Bunu temkinli kullanın, çünkü prototipin özelliklerini yazdırabilir obj

7 ES7 yaklaşımı

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

}

Ancak, düzenleme sırasında ES7 yöntemini önermem, çünkü JavaScript bu prosedürü oluşturmak için dahili olarak çok sayıda değişken başlatır (kanıt için geri bildirimlere bakın). Eğer optimizasyonu hak eden büyük bir uygulama geliştirmiyorsanız, o zaman tamam ama optimizasyon önceliğinizse bunu düşünmelisiniz.

II. sadece her bir değere erişmemiz gerekiyor,

And ofve Object.valuesyaklaşımı

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

}

Testler hakkında daha fazla geri bildirim:

  • Önbellekleme Object.keysveya Object.valuesperformans göz ardı edilebilir

Örneğin,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Örneğin Object.values, forFirefox'ta önbelleğe alınmış değişkenlere sahip yerel bir for...ofdöngü kullanmak, döngü kullanmaktan biraz daha hızlı görünüyor . Ancak fark o kadar da önemli değil ve Chrome for...ofyerel fordöngüden daha hızlı çalışıyor , bu nedenle her durumda (4. ve 6. testler) for...ofuğraşırken kullanmanızı tavsiye ederim Object.values.

  • Firefox'ta, for...indöngü gerçekten yavaştır, bu nedenle anahtarı yineleme sırasında önbelleğe almak istediğimizde kullanmak daha iyidir Object.keys. Ayrıca Chrome her iki yapıyı da eşit hızda çalıştırıyor (1. ve son testler).

Testleri buradan kontrol edebilirsiniz: https://jsperf.com/es7-and-misc-loops


2
ES7 örneği React Native ile bir cazibe gibi çalışıyor!
Ty Bailey

Güzel açıkladı. Teşekkürler
Alok Ranjan

30

Waaay'ın geç olduğunu biliyorum, ama AgileJon'un cevabının bu optimize edilmiş ve geliştirilmiş versiyonunu yazmak 2 dakikamı aldı:

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
Neden depoladığınız hasOwnPropertyiçinde ownsve daha sonra arayarak owns.call(obj, prop)arayarak hemen yerine obj.hasOwnProperty(prop)olarak bu cevabı nedir?
Rory O'Kane

14
Çünkü üzerinde kendinden tanımlı fonksiyon objolabilir, bu hasOwnPropertyyüzden onu kullanmayacaktır Object.prototype. Döngüden önce forböyle deneyebilirsiniz obj.hasOwnProperty = function(){return false;}ve herhangi bir özellik üzerinde yinelenmez.
Azder

4
@Azder +1 için cevap ve +1 için Object.prototype.hasOwnProperty hakkında güzel bir şey olabilir. Bunu daha önce alt çizgi kütüphanesinin kaynak kodunun içinde gördüm ama nedenini bilmiyorum.
Samuel

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

p değerdir

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

VEYA

Object.keys(p).forEach(key => { console.log(key, p[key]) })

9

ES7'de şunları yapabilirsiniz:

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

Bazı testler yaptım, bu yöntem büyük miktarda veriyle uğraşırken gerçekten yavaş.
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

Bunu yapmanın birkaç yolu ...

1) Döngüde ... için 2 katman ...

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

2) kullanmaObject.key

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

3) Özyinelemeli işlev

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

Ve şöyle deyin:

recursiveObj(validation_messages);

5

İşte AgileJon'un çözümünün ( demo ) geliştirilmiş ve özyinelemeli sürümü geliyor :

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

Bu çözüm her türlü farklı derinlik için çalışır.


5

Başka seçenek:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}

Çözümünüzü Chrome 55.0'da denedim ve bir tür hata alıyorsunuz. Cevabınız güzel ve özlü görünüyor, eğer çalıştırabilirseniz muhtemelen daha iyi seçeneklerden biri olacaktır. Anlamaya çalıştım ama çözümünüzü anlamıyorum.
TolMera

2
@TolMera Düzeltildi.
ahbap

4

ECMAScript-2017, bir ay önce sonlandırıldı, Object.values ​​() öğesini tanıtıyor. Şimdi bunu yapabilirsiniz:

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

3

Bence jQuery bu güzel ile sıralar işaret değer $.each() .

Bkz. Https://api.jquery.com/each/

Örneğin:

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

$(this)nesnenin içindeki tek öğe. JQuery'nin $('.foo')seçici motorunu kullanmak istemiyorsanız bir değişkenle değiştirin.


3

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

JavaScript Nesnesi arasında geçiş yapmak için forEach kullanabilir ve kodu optimize etmek için ok işlevini kullanabiliriz


2

Yukarıdaki mesajları tam olarak ne olduğumu yapamadım.

Burada diğer cevaplarla oynadıktan sonra bunu yaptım. Kibirli ama işe yarıyor!

Bu nesne için:

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

... bu kod:

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

... bunu konsolda üretir:

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

0

Benim için çalışan çözüm şudur:

_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

Egzotik Bir - Derin Travers

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

  // ... your code

  return value;
})

Bu çözümde tüm nesnenin ve iç içe nesnelerin derinlemesine hareket etmesini sağlayan replacer kullanıyoruz - her seviyede tüm alanları ve değerleri alacaksınız. Her alana tam yol almanız gerekiyorsa buraya bakın


-6

Benim durumumda (öncekilere dayanarak) herhangi bir sayıda seviye mümkündür.

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

sonuç:

["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"]
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.