Bagaimana cara loop melalui objek JavaScript biasa dengan objek sebagai anggota?

1601

Bagaimana saya bisa mengulang semua anggota dalam objek JavaScript termasuk nilai-nilai yang merupakan objek.

Misalnya, bagaimana saya bisa mengulanginya (mengakses "nama_Anda" dan "pesan_Anda" untuk masing-masing)?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}
edt
sumber
11
kemungkinan duplikat objek Loop through JavaScript
BuZZ-dEE

Jawaban:

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
sumber
13
Internet Explorer tidak setuju ( desah ), mengatakan "Objek tidak mendukung properti atau metode ini" ketika Anda melakukan obj [prop]. Saya belum menemukan solusi untuk ini.
user999717
2
@MildFuzz sebenarnya masuk akal jika Anda menganggap bahwa objek JS tidak perlu memiliki kunci numerik. Anda tidak bisa hanya beralih melalui objek. JS for insangat mirip dengan tradisional foreach.
Jake Wilson
4
for ... in adalah solusi yang baik, tetapi jika Anda menggunakan janji dalam for () - loop berhati-hatilah, karena jika Anda membuat var dalam loop, Anda tidak dapat menggunakannya dalam fungsi-janji yang dijanjikan. Anda var dalam loop hanya ada satu kali, sehingga memiliki di setiap-fungsi yang sama, bahkan nilai terakhir. Jika Anda memiliki masalah itu, coba "Object.keys (obj) .forEach" atau jawaban saya di bawah ini.
Biber
hasOwnProperty hampir selalu berlebihan untuk browser modern (IE9 +).
Filyus
775

Di bawah ECMAScript 5, Anda dapat menggabungkan Object.keys()dan 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
sumber
34
+1 untuk singkatnya kode tetapi tampaknya, tidak berkinerja seefisien untuk secara mengejutkan. JSPerf - untuk di dalam vs Object.keys
techiev2
6
Waspadalah terhadap kesalahan ini menggunakan pendekatan ini: "TypeError: Object.keys memanggil non-objek". The for ... in ... hasOwnPropertypola dapat disebut pada apa pun, sejauh yang saya tahu (objek, array, null, terdefinisi, true, false, nomor primitif, objek).
theazureshadow
2
Perhatikan bahwa IE7 tidak mendukung ini.
Paul D. Waite
3
@ techiev2 tes-tes itu tidak pernah valid. Lihat pembaruan saya untuk kondisi kinerja saat ini: jsperf.com/objdir/20
OrganicPanda
4
@ techiev2: ini bukan Object.keys()yang membuatnya lambat, ini lebih merupakan forEach()dan akses berulang ke .length! Jika Anda menggunakan klasik for-loop sebaliknya, itu hampir dua kali lebih cepat for..in+ hasOwnProperty()di Firefox 33.
CodeManX
384

Masalahnya dengan ini

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

adalah bahwa Anda juga akan mengulang melalui prototipe objek primitif.

Dengan ini, Anda akan menghindarinya:

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
sumber
46
Singkatnya: periksa hasOwnPropertydi dalam for- inloop Anda.
Rory O'Kane
59
Perhatikan bahwa ini hanya diperlukan jika objek Anda memiliki metode prototipe. Misalnya, jika objek yang Anda lewati hanyalah objek JSON, Anda tidak akan memerlukan pemeriksaan ini.
gitaarik
6
@rednaw Agar aman saya menggunakan pemeriksaan itu karena Object.prototype dapat dimodifikasi. Tidak ada skrip waras yang akan melakukan itu, tetapi Anda tidak dapat mengontrol skrip apa yang mungkin dijalankan di halaman Anda dengan ekstensi peramban yang tidak waras. Ekstensi peramban berjalan di laman Anda (di sebagian besar peramban) dan dapat menyebabkan masalah aneh (mis. Set window.setTimeout ke null!).
robocat
1
Terima kasih banyak
Trem Biru
328

Dalam ES6 / 2015 Anda dapat mengulangi objek seperti ini: (menggunakan fungsi panah )

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

Di ES7 / 2016 Anda bisa menggunakan dan Object.entriesbukan Object.keysmelalui objek seperti ini:

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

Di atas juga akan berfungsi sebagai satu-liner :

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

jsbin

Jika Anda ingin mengulangi objek bersarang juga, Anda dapat menggunakan fungsi rekursif (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

Sama seperti fungsi di atas, tetapi dengan ES7 Object.entries() bukannya 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.
  });
};

Di sini kita loop melalui objek bersarang mengubah nilai dan mengembalikan objek baru dalam sekali pakai menggunakan Object.entries()dikombinasikan dengan 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
sumber
2
untuk ES7 Anda menggunakan contoh Object.entries, Anda perlu membungkus parameter fungsi panah [kunci, val] dalam tanda kurung seperti: `Object.entries (myObj) .forEach (([kunci, val]) => {/ * pernyataan * /}
puiu
6
Saya pikir akan berguna untuk menambahkan fakta bahwa Object.entries dan Object.keys tidak mengulangi prototipe yang merupakan perbedaan besar antara itu dan untuk dalam konstruksi.
steviejay
Terima kasih banyak
Trem Biru
95

Menggunakan Underscore.js_.each :

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});
Tim Santeford
sumber
4
Terima kasih Tim, menggunakan garis bawah jadi pasti bagus untuk memiliki opsi yang cepat dan bersih.
The Coder
56

Jika Anda menggunakan rekursi, Anda dapat mengembalikan properti objek dari kedalaman apa pun.

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
sumber
2
Waspadalah terhadap loop, seperti memanggil ini pada simpul DOM.
theazureshadow
45

Jawaban ini adalah agregat dari solusi yang disediakan dalam posting ini dengan beberapa umpan balik kinerja . Saya pikir ada 2 use-case dan OP tidak menyebutkan apakah dia perlu mengakses kunci untuk menggunakannya selama proses loop.

I. kunci perlu diakses,

ofdan Object.keyspendekatan

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

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

inpendekatannya

let k;
for (k in obj) {

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

Gunakan yang ini dengan hati-hati, karena dapat mencetak properti prototipe dari obj

✔ pendekatan ES7

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

}

Namun, pada saat edit saya tidak akan merekomendasikan metode ES7, karena JavaScript menginisialisasi banyak variabel secara internal untuk membangun prosedur ini (lihat umpan balik sebagai bukti). Kecuali jika Anda tidak mengembangkan aplikasi besar yang perlu dioptimalkan, maka itu boleh saja tetapi jika optimasi adalah prioritas Anda, Anda harus memikirkannya.

II kita hanya perlu mengakses setiap nilai,

ofdan Object.valuespendekatan

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

}

Umpan balik lebih lanjut tentang tes:

  • Caching Object.keysatau Object.valueskinerja dapat diabaikan

Contohnya,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Sebagai Object.valuescontoh, menggunakan forloop asli dengan variabel yang di-cache di Firefox tampaknya sedikit lebih cepat daripada menggunakan for...ofloop. Namun perbedaannya tidak begitu penting dan Chrome berjalan for...oflebih cepat dari forloop asli , jadi saya akan merekomendasikan untuk digunakan for...ofketika berhadapan dengan Object.valueskasus apa pun (tes ke-4 dan ke-6).

  • Di Firefox, for...inloopnya sangat lambat, jadi ketika kami ingin men-cache kunci selama iterasi, lebih baik digunakan Object.keys. Plus Chrome menjalankan kedua struktur dengan kecepatan yang sama (tes 1 dan terakhir).

Anda dapat memeriksa tes di sini: https://jsperf.com/es7-and-misc-loops

vdegenne
sumber
2
Contoh ES7 bekerja seperti pesona dengan React Native!
Ty Bailey
Dijelaskan dengan baik. Terima kasih
Alok Ranjan
30

Saya tahu ini terlambat, tetapi saya butuh waktu 2 menit untuk menulis versi AgileJon yang dioptimalkan dan diperbaiki ini:

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
sumber
1
Mengapa Anda menyimpan hasOwnPropertydalam ownsdan kemudian memanggil owns.call(obj, prop)bukan hanya menyebut obj.hasOwnProperty(prop)sebagai jawaban ini tidak?
Rory O'Kane
14
Karena objmungkin memiliki hasOwnPropertyfungsi yang didefinisikan pada dirinya sendiri sehingga tidak akan menggunakan yang dari Object.prototype. Anda dapat mencoba sebelum forloop seperti ini obj.hasOwnProperty = function(){return false;}dan tidak akan mengulangi properti apa pun.
Azder
4
@Azder +1 untuk jawabannya dan +1 jika saya bisa untuk hal yang menyenangkan tentang Object.prototype.hasOwnProperty. Saya melihat itu sebelumnya di dalam kode sumber perpustakaan garis bawah tetapi tidak tahu mengapa.
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);
}
kekacauan
sumber
14

p adalah nilainya

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

ATAU

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

Di ES7 Anda dapat melakukan:

for (const [key, value] of Object.entries(obj)) {
  //
}
Kévin Berthommier
sumber
Saya melakukan beberapa tes, metode ini sangat lambat ketika berhadapan dengan sejumlah besar data.
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
sumber
7

Beberapa cara untuk melakukan itu ...

1) 2 lapisan untuk ... dalam lingkaran ...

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

2) MenggunakanObject.key

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

3) Fungsi rekursif

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

Dan menyebutnya seperti:

recursiveObj(validation_messages);
Alireza
sumber
5

Di sinilah versi perbaikan dan rekursif dari solusi 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);

Solusi ini bekerja untuk semua jenis kedalaman yang berbeda.

JepZ
sumber
5

Pilihan lain:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}
kawan
sumber
Saya mencoba solusi Anda di Chrome 55.0 dan Anda mendapatkan kesalahan ketik. Jawaban Anda terlihat bagus dan ringkas, jika Anda bisa membuatnya berfungsi, itu mungkin salah satu pilihan yang lebih baik. Saya mencoba mencari tahu tapi tidak mengerti solusi Anda.
TolMera
2
@TolMera Diperbaiki.
Bung
4

ECMAScript-2017, baru saja selesai sebulan lalu, memperkenalkan Object.values ​​(). Jadi sekarang Anda bisa melakukan ini:

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

Saya pikir itu layak menunjukkan bahwa jQuery menyelesaikan masalah ini dengan baik $.each().

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

Sebagai contoh:

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

$(this)menjadi item tunggal di dalam objek. Tukar $('.foo')ke variabel jika Anda tidak ingin menggunakan mesin pemilih jQuery.

Daniel Dewhurst
sumber
3

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

Untuk mengulang melalui objek JavaScript kita dapat menggunakan forEach dan untuk mengoptimalkan kode kita dapat menggunakan fungsi panah

Sandip Bailkar
sumber
2

Saya tidak bisa mendapatkan posting di atas untuk melakukan apa yang saya inginkan.

Setelah bermain-main dengan balasan lain di sini, saya membuat ini. Ini hacky, tetapi berhasil!

Untuk objek ini:

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

... kode ini:

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

... menghasilkan ini di konsol:

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

Solusi yang bekerja untuk saya adalah sebagai berikut

_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
sumber
0

Eksotis satu - melintasi mendalam

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

  // ... your code

  return value;
})

Dalam solusi ini kami menggunakan replacer yang memungkinkan untuk melintasi seluruh objek dan objek bersarang - pada setiap level Anda akan mendapatkan semua bidang dan nilai. Jika Anda perlu mendapatkan path lengkap ke setiap bidang, lihat di sini

Kamil Kiełczewski
sumber
-6

Dalam kasus saya (atas dasar sebelumnya) dimungkinkan sejumlah tingkat.

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

hasil:

["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"]
pengguna2515312
sumber