Jak przejść przez zwykły obiekt JavaScript z obiektami jako członkami?


1599

Jak mogę zapętlić wszystkie elementy w obiekcie JavaScript, w tym wartości będące obiektami.

Na przykład, w jaki sposób mogę przez to przejść (uzyskując dostęp do „nazwa_użytkownika” i „nazwa_użytkownika” dla każdego z nich)?

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

Odpowiedzi:


2112
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
Internet Explorer nie zgadza się ( wzdycha ), mówi „Obiekt nie obsługuje tej właściwości lub metody” podczas wykonywania obj [prop]. Muszę jeszcze znaleźć rozwiązanie tego problemu.
user999717,

2
@MildFuzz ma sens, jeśli weźmiesz pod uwagę, że obiekty JS nie muszą mieć klawiszy numerycznych. Nie możesz po prostu iterować przez obiekt. JS for injest bardzo podobny do tradycyjnego foreach.
Jake Wilson

4
for ... in jest dobrym rozwiązaniem, ale jeśli używasz obietnic w pętli for (), zachowaj ostrożność, ponieważ jeśli utworzysz var w pętli, nie będziesz mógł jej użyć w funkcji obietnicy. Twoja zmienna w pętli istnieje tylko raz, więc ma w każdej funkcji wtedy tę samą, nawet ostatnią wartość. Jeśli masz ten problem, wypróbuj „Object.keys (obj) .forEach” lub moją odpowiedź poniżej.
Biber,

775

W ECMAScript 5 możesz łączyć Object.keys()i 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 za zwięzłość kodu, ale najwyraźniej nie działa tak skutecznie jak zaskakująco. JSPerf - for in vs Object.keys
techiev2 2

6
Uważaj na ten błąd, stosując następujące podejście: „TypeError: Object.keys wywołany na obiekcie innym niż obiekt”. for ... in ... hasOwnPropertyWzór można nazwać na niczym, o ile mogę powiedzieć (obiekt, array, null, niezdefiniowane, true, false, numer prymitywne, obiekty).
theazureshadow

2
Zauważ, że IE7 tego nie obsługuje.
Paul D. Waite,

3
@ techiev2 te testy nigdy nie były ważne. Zobacz moje zaktualizowane aktualne wyniki: jsperf.com/objdir/20
OrganicPanda

4
@ techiev2: to nie Object.keys()jest powolne, to raczej ciągły forEach()dostęp do .length! Jeśli forzamiast tego użyjesz klasycznej pętli, w przeglądarce Firefox 33 jest ona prawie dwa razy szybsza niż for..in+.hasOwnProperty()
CodeManX,

384

Problem z tym

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

polega na tym, że będziesz również przechodzić przez prototyp pierwotnego obiektu.

Dzięki temu unikniesz tego:

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
W skrócie: sprawdzić hasOwnPropertywewnątrz firmy for- inpętle.
Rory O'Kane

59
Należy pamiętać, że jest to konieczne tylko wtedy, gdy obiekt HAS ma metody prototypowe. Na przykład, jeśli zapętlony obiekt jest tylko obiektem JSON, nie będziesz potrzebować tego sprawdzania.
gitaarik

6
@rednaw Dla bezpieczeństwa używam tego wyboru, ponieważ Object.prototype można modyfikować. Nie zrobiłby tego żaden rozsądny skrypt, ale nie możesz kontrolować, jakie skrypty mogą być uruchamiane na twojej stronie przez szalone rozszerzenia przeglądarki. Rozszerzenia przeglądarki działają na twojej stronie (w większości przeglądarek) i mogą powodować dziwne problemy (np. Ustaw window.setTimeout na zero!).
robocat,

1
Dziękuję bardzo
Blue Tram

328

W ES6 / 2015 możesz przechodzić przez taki obiekt: (używając funkcji strzałki )

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

W ES7 / 2016 możesz używać Object.entrieszamiast tego Object.keysi przechodzić przez taki obiekt:

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

Powyższe działałoby również jako jednolinijka :

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

jsbin

Jeśli chcesz również zapętlić zagnieżdżone obiekty, możesz użyć funkcji rekurencyjnej (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

Taki sam jak funkcja powyżej, ale z ES7 Object.entries() zamiast 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.
  });
};

Tutaj przechodzimy przez obiekty zagnieżdżone, zmieniamy wartości i zwracamy nowy obiekt za jednym razem, używając w Object.entries()połączeniu z 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.
    })
  );

2
dla Twojego ES7 na przykładzie Object.entries, musisz owinąć parametry funkcji strzałek [key, val] w nawiasach takich jak: `Object.entries (myObj) .forEach (([[key, val]) => instrukcje {/ * * /}
puiu

6
Myślę, że użyteczne byłoby dodanie faktu, że Object.entries i Object.keys nie iterują po prototypie, co stanowi dużą różnicę między nim a konstrukcją for.
steviejay

Dziękuję bardzo
Blue Tram

95

Korzystanie z Underscore.js_.each :

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

4
Dzięki Tim, użycie podkreślenia jest tak dobre, aby mieć szybką i czystą opcję.
The Coder

56

Jeśli użyjesz rekurencji, możesz zwrócić właściwości obiektu o dowolnej głębokości

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
Uwaga na pętle, takie jak wywoływanie tego w węźle DOM.
theazureshadow

45

Ta odpowiedź jest agregacją rozwiązań, które zostały dostarczone w tym poście z pewnymi sprzężeniami zwrotnymi dotyczącymi wydajności . Myślę, że istnieją 2 przypadki użycia, a OP nie wspomniał o tym, czy musi uzyskać dostęp do kluczy, aby użyć ich podczas procesu pętli.

I. klucze muszą być dostępne,

ofi Object.keyspodejście

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

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

inpodejście

let k;
for (k in obj) {

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

Używaj tego z ostrożnością, ponieważ może wydrukować właściwości prototypu obj

✔ podejście ES7

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

}

Jednak podczas edycji nie polecałbym metody ES7, ponieważ JavaScript inicjuje wiele zmiennych wewnętrznie, aby zbudować tę procedurę (zobacz dowody zwrotne dla potwierdzenia). Jeśli nie tworzysz ogromnej aplikacji, która zasługuje na optymalizację, jest w porządku, ale jeśli optymalizacja jest twoim priorytetem, powinieneś o tym pomyśleć.

II. musimy tylko uzyskać dostęp do każdej wartości,

ofi Object.valuespodejście

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

}

Więcej informacji zwrotnych na temat testów:

  • Buforowanie Object.keyslub Object.valueswydajność jest znikoma

Na przykład,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Na Object.valuesprzykład użycie natywnej forpętli ze zmiennymi buforowanymi w Firefoksie wydaje się nieco szybsze niż użycie for...ofpętli. Różnica nie jest jednak tak ważna, a Chrome działa for...ofszybciej niż natywna forpętla, dlatego polecam korzystać for...ofz niej Object.valuesw każdym przypadku (4. i 6. test).

  • W przeglądarce Firefox for...inpętla jest bardzo wolna, więc jeśli chcemy buforować klucz podczas iteracji, lepiej jest go użyć Object.keys. Dodatkowo Chrome działa na obu strukturach z jednakową prędkością (pierwszy i ostatni test).

Możesz sprawdzić testy tutaj: https://jsperf.com/es7-and-misc-loops


2
Przykład ES7 działa jak urok w React Native!
Ty Bailey,

Ładnie wyjaśnione. Dzięki
Alok Ranjan

30

Wiem, że jest późno, ale napisanie tej zoptymalizowanej i ulepszonej wersji odpowiedzi AgileJon zajęło mi 2 minuty:

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
Czemu przechowywania hasOwnPropertyw owns, a następnie wywołanie owns.call(obj, prop)zamiast po prostu wywołanie obj.hasOwnProperty(prop)jak ta odpowiedź robi?
Rory O'Kane

14
Ponieważ objmoże mieć hasOwnPropertyzdefiniowaną funkcję na sobie, więc nie będzie korzystać z tej z Object.prototype. Możesz wypróbować przed taką forpętlą obj.hasOwnProperty = function(){return false;}i nie będzie iterować po żadnej właściwości.
Azder

4
@Azder +1 za odpowiedź i +1, gdybym mógł za fajną rzecz w Object.prototype.hasOwnProperty. Widziałem to wcześniej w kodzie źródłowym biblioteki podkreślenia, ale nie wiem dlaczego.
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 jest wartością

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

LUB

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

9

W ES7 możesz wykonać:

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

Zrobiłem kilka testów, ta metoda jest naprawdę powolna w przypadku dużej ilości danych.
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

Niewiele sposobów na zrobienie tego ...

1) 2 warstwy dla ... w pętli ...

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

2) KorzystanieObject.key

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

3) Funkcja rekurencyjna

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

I nazwij to tak:

recursiveObj(validation_messages);

5

Oto ulepszona i rekurencyjna wersja rozwiązania 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);

To rozwiązanie działa na różnego rodzaju głębokościach.


5

Inna opcja:

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

Wypróbowałem twoje rozwiązanie w Chrome 55.0 i pojawia się błąd typu. Twoja odpowiedź wygląda ładnie i zwięźle, jeśli uda ci się ją uruchomić, prawdopodobnie będzie to jedna z lepszych opcji. Próbowałem to rozgryźć, ale nie rozumiem twojego rozwiązania.
TolMera

2
@TolMera Naprawiono.
koleś

4

ECMAScript-2017, właśnie ukończony miesiąc temu, wprowadza Object.values ​​(). Teraz możesz to zrobić:

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

3

Myślę, że warto zauważyć, że jQuery ładnie to rozwiązuje $.each().

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

Na przykład:

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

$(this)będąc pojedynczym przedmiotem wewnątrz obiektu. Zamień $('.foo')na zmienną, jeśli nie chcesz używać silnika wyboru jQuery.


3

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

Do przechodzenia przez obiekt JavaScript możemy użyć forEach, a do optymalizacji kodu możemy użyć funkcji strzałki


2

Nie mogłem nakłonić powyższych postów do zrobienia tego, o co mi chodziło.

Po przeanalizowaniu innych odpowiedzi tutaj zrobiłem to. Jest hacky, ale działa!

Dla tego obiektu:

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

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

... tworzy to w konsoli:

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

0

Rozwiązanie, które działa dla mnie, jest następujące

_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

Egzotyczny - głęboki trawers

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

  // ... your code

  return value;
})

W tym rozwiązaniu wykorzystujemy zamiennik, który pozwala na głębokie przemierzanie całego obiektu i obiektów zagnieżdżonych - na każdym poziomie otrzymasz wszystkie pola i wartości. Jeśli potrzebujesz uzyskać pełną ścieżkę do każdego pola, spójrz tutaj


-6

W moim przypadku (na podstawie powyższego) możliwa jest dowolna liczba poziomów.

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

wynik:

["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"]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.