Wie durchlaufe ich ein einfaches JavaScript-Objekt mit den Objekten als Mitgliedern?

1600

Wie kann ich alle Elemente in einem JavaScript-Objekt durchlaufen, einschließlich der Werte, die Objekte sind?

Wie könnte ich dies beispielsweise durchlaufen (Zugriff auf "your_name" und "your_message" für jede)?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}
Sommerzeit
quelle
11
Mögliches Duplikat der Schleife durch JavaScript-Objekt
BuZZ-dEE

Antworten:

2114
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
quelle
13
Internet Explorer stimmt nicht zu ( seufzt ) und sagt, dass "Object diese Eigenschaft oder Methode nicht unterstützt", wenn Sie obj [prop] ausführen. Ich habe noch keine Lösung dafür gefunden.
user999717
2
@MildFuzz Eigentlich ist es sinnvoll, wenn man bedenkt, dass JS-Objekte keine numerischen Schlüssel haben müssen. Sie können nicht einfach durch ein Objekt iterieren. JS for inist einem traditionellen sehr ähnlich foreach.
Jake Wilson
4
for ... in ist eine gute Lösung, aber wenn Sie Versprechen in der for () - - Schleife verwenden, seien Sie vorsichtig, denn wenn Sie ein var in der Schleife erstellen, können Sie es nicht in der then-Funktion des Versprechens verwenden. Sie var in der Schleife existiert nur einmal, also hat es in jeder then-Funktion den gleichen, sogar den letzten Wert. Wenn Sie dieses Problem haben, versuchen Sie "Object.keys (obj) .forEach" oder meine Antwort unten.
Biber
hasOwnProperty ist für moderne Browser (IE9 +) fast immer redundant.
Filyus vor
775

Unter ECMAScript 5 können Sie kombinieren Object.keys()und 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]);

});

Axel Rauschmayer
quelle
34
+1 für die Kürze des Codes, aber anscheinend nicht so effizient wie für überraschend. JSPerf - für in vs Object.keys
techiev2
6
Achten Sie bei diesem Ansatz auf diesen Fehler: "TypeError: Object.keys, die für Nichtobjekte aufgerufen werden". Das for ... in ... hasOwnPropertyMuster kann auf alles aufgerufen werden, soweit ich das beurteilen kann (Objekt, Array, Null, undefiniert, wahr, falsch, Zahlenprimitiv, Objekte).
Theazureshadow
2
Beachten Sie, dass IE7 dies nicht unterstützt.
Paul D. Waite
3
@ techiev2 diese Tests waren nie gültig. Siehe meine aktualisierten für den aktuellen Leistungsstatus: jsperf.com/objdir/20
OrganicPanda
4
@ techiev2: es ist nicht Object.keys()das, was es langsam macht, es ist eher das forEach()und der wiederholte Zugriff auf .length! Wenn Sie forstattdessen eine klassische Schleife verwenden, ist diese fast doppelt so schnell wie for..in+ hasOwnProperty()in Firefox 33.
CodeManX
384

Das Problem damit

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

ist, dass Sie auch den Prototyp des primitiven Objekts durchlaufen.

Mit diesem vermeiden Sie es:

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
quelle
46
Kurz gesagt: Überprüfen Sie hasOwnPropertyIhre for- inSchleifen.
Rory O'Kane
59
Beachten Sie, dass dies nur erforderlich ist, wenn Ihr Objekt Prototypmethoden hat. Wenn das Objekt, das Sie durchlaufen, beispielsweise nur ein JSON-Objekt ist, benötigen Sie diese Prüfung nicht.
Gitaarik
6
@rednaw Um sicher zu gehen, verwende ich diese Prüfung, da Object.prototype geändert werden kann. Kein vernünftiges Skript würde dies tun, aber Sie können nicht steuern, welche Skripte auf Ihrer Seite durch verrückte Browsererweiterungen ausgeführt werden. Browsererweiterungen werden auf Ihrer Seite ausgeführt (in den meisten Browsern) und können seltsame Probleme verursachen (z. B. setzen Sie window.setTimeout auf null!).
Robocat
1
Vielen Dank
Blue Tram
328

In ES6 / 2015 können Sie ein Objekt wie folgt durchlaufen: (mithilfe der Pfeilfunktion )

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 können Sie verwenden Object.entriesstatt Object.keysund Schleife durch ein Objekt wie folgt aus :

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

Das Obige würde auch als Einzeiler funktionieren :

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

jsbin

Wenn Sie auch verschachtelte Objekte durchlaufen möchten, können Sie eine rekursive Funktion (ES6) verwenden:

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

Wie oben beschrieben, jedoch mit ES7 Object.entries() anstelle von 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.
  });
};

Hier durchlaufen wir verschachtelte Objekte, ändern Werte und geben ein neues Objekt auf einmal zurück, indem wir es Object.entries()mit Object.fromEntries()( ES10 / 2019 ) kombinieren :

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
quelle
2
Für Ihr ES7-Beispiel mit Object.entries müssen Sie die Pfeilfunktionsparameter [key, val] in Klammern setzen wie: `Object.entries (myObj) .forEach (([key, val]) => {/ * Anweisungen * /}
Puiu
6
Ich denke, es wäre nützlich, die Tatsache hinzuzufügen, dass Object.entries und Object.keys nicht über den Prototyp iterieren, was den großen Unterschied zwischen ihm und dem for in-Konstrukt darstellt.
Steviejay
Vielen Dank
Blue Tram
95

Verwenden von Underscore.js_.each :

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});
Tim Santeford
quelle
4
Vielen Dank, Tim, mit dem Unterstrich ist es auf jeden Fall gut, eine schnelle und saubere Option zu haben.
Der Kodierer
56

Wenn Sie die Rekursion verwenden, können Sie Objekteigenschaften beliebiger Tiefe zurückgeben.

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
quelle
2
Achten Sie auf Schleifen, wie sie auf einem DOM-Knoten aufgerufen werden.
Theazureshadow
45

Diese Antwort ist eine Zusammenfassung der Lösungen, die in diesem Beitrag mit einigen Leistungsrückmeldungen bereitgestellt wurden . Ich denke, es gibt zwei Anwendungsfälle, und das OP hat nicht erwähnt, ob er auf die Schlüssel zugreifen muss, um sie während des Schleifenprozesses zu verwenden.

I. Auf die Schlüssel muss zugegriffen werden.

✔ die ofund Object.keysAnsatz

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

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

✔ der inAnsatz

let k;
for (k in obj) {

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

Verwenden Sie dieses mit Vorsicht, da es prototypische Eigenschaften von drucken könnte obj

✔ der ES7-Ansatz

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

}

Zum Zeitpunkt der Bearbeitung würde ich die ES7-Methode jedoch nicht empfehlen, da JavaScript viele Variablen intern initialisiert, um diese Prozedur zu erstellen (Beweise finden Sie in den Rückmeldungen). Wenn Sie keine große App entwickeln, die eine Optimierung verdient, ist dies in Ordnung. Wenn jedoch die Optimierung Ihre Priorität ist, sollten Sie darüber nachdenken.

II. wir müssen nur auf jeden Wert zugreifen,

✔ die ofund Object.valuesAnsatz

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

}

Weitere Rückmeldungen zu den Tests:

  • Caching Object.keysoder Object.valuesLeistung ist vernachlässigbar

Zum Beispiel,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Für Object.valuesFall einer native Verwendung forscheint Schleife mit zwischengespeicherten Variablen in Firefox ein wenig schneller zu sein als eine mit for...ofSchleife. Allerdings ist der Unterschied nicht so wichtig , und Chrome läuft for...ofschneller als nativer forSchleife, so dass ich zu Verwendung empfehlen würde , for...ofwenn sie mit den Umgang Object.valuesin allen Fällen (4. und 6. Tests).

  • In Firefox ist die for...inSchleife sehr langsam. Wenn wir den Schlüssel während der Iteration zwischenspeichern möchten, ist es besser, ihn zu verwenden Object.keys. Plus Chrome führt beide Strukturen mit gleicher Geschwindigkeit aus (1. und letzter Test).

Sie können die Tests hier überprüfen: https://jsperf.com/es7-and-misc-loops

vdegenne
quelle
2
Das ES7-Beispiel funktioniert wie ein Zauber mit React Native!
Ty Bailey
Schön erklärt. Vielen Dank
Alok Ranjan
30

Ich weiß, dass es spät ist, aber ich habe 2 Minuten gebraucht, um diese optimierte und verbesserte Version von AgileJons Antwort zu schreiben:

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
quelle
1
Warum speichern Sie hasOwnPropertyin ownsund rufen dann an, owns.call(obj, prop)anstatt nur anzurufen, obj.hasOwnProperty(prop)wie es diese Antwort tut?
Rory O'Kane
14
Da objdie hasOwnPropertyFunktion möglicherweise selbst definiert ist, wird die Funktion von nicht verwendet Object.prototype. Sie können es vor der forSchleife wie obj.hasOwnProperty = function(){return false;}folgt versuchen und es wird keine Eigenschaft durchlaufen.
Azder
4
@ Azder +1 für die Antwort und +1, wenn ich für die nette Sache über Object.prototype.hasOwnProperty könnte. Ich habe das zuvor im Quellcode der Unterstrichbibliothek gesehen, weiß aber nicht warum.
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);
}
Chaos
quelle
14

p ist der Wert

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

ODER

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

In ES7 können Sie Folgendes tun:

for (const [key, value] of Object.entries(obj)) {
  //
}
Kévin Berthommier
quelle
Ich habe einige Tests durchgeführt. Diese Methode ist sehr langsam, wenn große Datenmengen verarbeitet werden.
Vdegenne
8
for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}
Dmitri Farkov
quelle
7

Nur wenige Möglichkeiten, das zu tun ...

1) 2 Schichten für ... in Schleife ...

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

2) VerwendenObject.key

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

3) Rekursive Funktion

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

Und nenne es wie:

recursiveObj(validation_messages);
Alireza
quelle
5

Hier kommt die verbesserte und rekursive Version der AgileJon-Lösung ( 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);

Diese Lösung funktioniert für alle Arten von unterschiedlichen Tiefen.

JepZ
quelle
5

Andere Option:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}
Kumpel
quelle
Ich habe Ihre Lösung in Chrome 55.0 ausprobiert und Sie erhalten einen Tippfehler. Ihre Antwort sieht gut und prägnant aus. Wenn Sie sie zum Laufen bringen können, ist sie wahrscheinlich eine der besseren Optionen. Ich habe versucht, es herauszufinden, verstehe aber Ihre Lösung nicht.
TolMera
2
@ TolMera behoben.
Typ
4

ECMAScript-2017, das erst vor einem Monat fertiggestellt wurde, führt Object.values ​​() ein. Jetzt können Sie Folgendes tun:

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

Ich denke, es ist erwähnenswert, dass jQuery dies gut regelt $.each().

Siehe: https://api.jquery.com/each/

Zum Beispiel:

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

$(this)ist das einzelne Element innerhalb des Objekts. Wechseln Sie $('.foo')zu einer Variablen, wenn Sie die Selector-Engine von jQuery nicht verwenden möchten.

Daniel Dewhurst
quelle
3

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

Um das JavaScript-Objekt zu durchlaufen, können wir forEach verwenden und um den Code zu optimieren, können wir die Pfeilfunktion verwenden

Sandip Bailkar
quelle
2

Ich konnte die oben genannten Beiträge nicht dazu bringen, genau das zu tun, wonach ich gesucht hatte.

Nachdem ich mit den anderen Antworten hier herumgespielt hatte, machte ich das. Es ist hacky, aber es funktioniert!

Für dieses Objekt:

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

... dieser Code:

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

... erzeugt dies in der Konsole:

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

Die Lösung, die für mich funktioniert, ist die folgende

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

Exotisch - tiefe Traverse

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

  // ... your code

  return value;
})

In dieser Lösung verwenden wir einen Ersetzer , mit dem ganze Objekte und verschachtelte Objekte tief durchlaufen werden können. Auf jeder Ebene erhalten Sie alle Felder und Werte. Wenn Sie den vollständigen Pfad zu jedem Feld benötigen, klicken Sie hier

Kamil Kiełczewski
quelle
-6

In meinem Fall (auf der Grundlage des Vorstehenden) ist eine beliebige Anzahl von Ebenen möglich.

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

Ergebnis:

["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
quelle