Làm thế nào để lặp qua một đối tượng JavaScript đơn giản với các đối tượng là thành viên?


1600

Làm cách nào tôi có thể lặp qua tất cả các thành viên trong một đối tượng JavaScript bao gồm các giá trị là các đối tượng.

Ví dụ: làm thế nào tôi có thể lặp qua điều này (truy cập vào "your_name" và "your_message" cho mỗi cái)?

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

Câu trả lời:


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

13
Internet Explorer không đồng ý ( thở dài ), nói rằng "Đối tượng không hỗ trợ thuộc tính hoặc phương thức này" khi bạn thực hiện obj [prop]. Tôi vẫn chưa tìm thấy một giải pháp cho điều này.
user999717

2
@MildFuzz thực sự có ý nghĩa nếu bạn cho rằng các đối tượng JS không cần thiết có các khóa số. Bạn không thể chỉ lặp qua một đối tượng. JS for inrất giống với truyền thống foreach.
Jake Wilson

4
for ... in là một giải pháp tốt, nhưng nếu bạn sử dụng lời hứa trong vòng lặp for () - hãy cẩn thận, bởi vì nếu bạn tạo một var trong vòng lặp, bạn không thể sử dụng nó trong chức năng của lời hứa. Bạn var trong vòng lặp chỉ tồn tại một lần, do đó, nó có trong mọi hàm sau đó giống nhau, thậm chí là giá trị cuối cùng. Nếu bạn gặp vấn đề đó, hãy thử "Object.keys (obj) .forEach" hoặc câu trả lời của tôi dưới đây.
Biber

hasOwnProperty hầu như luôn luôn dư thừa cho các trình duyệt hiện đại (IE9 +).
Filyus

775

Trong ECMAScript 5, bạn có thể kết hợp 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 cho sự ngắn gọn của mã nhưng rõ ràng, không hoạt động hiệu quả như đáng ngạc nhiên. JSPerf - for in vs Object.keys
techiev2

6
Cảnh giác với lỗi này khi sử dụng phương pháp này: "TypeError: Object.keys được gọi là phi đối tượng". Các for ... in ... hasOwnPropertymô hình có thể được gọi vào bất cứ điều gì, như xa như tôi có thể nói (đối tượng, mảng, null, undefined, đúng, sai, số nguyên thủy, các đối tượng).
theazureshadow

2
Lưu ý rằng IE7 không hỗ trợ này.
Paul D. Chờ

3
@ techiev2 những bài kiểm tra đó không bao giờ hợp lệ. Xem những bản cập nhật của tôi để biết trạng thái hiệu suất hiện tại: jsperf.com/objdir/20
OrganicPanda

4
@ techiev2: không phải là Object.keys()làm cho nó chậm, mà là forEach()truy cập nhiều lần .length! forThay vào đó, nếu bạn sử dụng một kiểu cổ điển , nó nhanh gấp đôi so với for..in+ hasOwnProperty()trong Firefox 33.
CodeManX

384

Vấn đề với điều này

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

là bạn cũng sẽ lặp qua nguyên mẫu của đối tượng nguyên thủy.

Với cái này bạn sẽ tránh được nó:

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
Tóm lại: kiểm tra hasOwnPropertybên trong for- invòng lặp của bạn .
Rory O'Kane

59
Lưu ý rằng điều này chỉ cần thiết nếu đối tượng của bạn có các phương thức nguyên mẫu. Ví dụ: nếu đối tượng bạn lặp qua chỉ là một đối tượng JSON, bạn sẽ không cần kiểm tra này.
gitaarik

6
@rednaw Để an toàn, tôi sử dụng kiểm tra đó vì Object.prototype có thể được sửa đổi. Không có tập lệnh lành mạnh nào làm được điều đó, nhưng bạn không thể kiểm soát tập lệnh nào có thể được chạy trong trang của mình bằng các tiện ích mở rộng trình duyệt điên rồ. Tiện ích mở rộng trình duyệt chạy trong trang của bạn (trên hầu hết các trình duyệt) và chúng có thể gây ra sự cố kỳ lạ (ví dụ: đặt window.setTimeout thành null!).
robocat

1
Cảm ơn bạn rất nhiều
Blue Trâm

328

Trong ES6 / 2015, bạn có thể lặp qua một đối tượng như thế này: (sử dụng chức năng mũi tên )

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

Trong ES7 / 2016, bạn có thể sử dụng Object.entriesthay vì Object.keysvà lặp qua một đối tượng như thế này:

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

Ở trên cũng sẽ hoạt động như một lớp lót :

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

jsbin

Trong trường hợp bạn cũng muốn lặp qua các đối tượng lồng nhau, bạn có thể sử dụng hàm đệ quy (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

Tương tự như chức năng trên, nhưng với ES7 Object.entries() thay vì 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.
  });
};

Ở đây chúng tôi lặp qua các đối tượng lồng nhau thay đổi giá trị và trả về một đối tượng mới trong một lần sử dụng Object.entries()kết hợp với 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
đối với ES7 của bạn bằng cách sử dụng ví dụ Object.entries, bạn cần bọc các tham số hàm mũi tên [key, val] trong ngoặc đơn như: `Object.entries (myObj) .forEach (([key, val]) => {/ * câu lệnh * /}
puiu

6
Tôi nghĩ sẽ hữu ích khi thêm một thực tế rằng Object.entries và Object.keys không lặp lại so với nguyên mẫu, đó là sự khác biệt lớn giữa nó và for trong xây dựng.
steviejay

Cảm ơn bạn rất nhiều
Blue Trâm

95

Sử dụng Underscore.js_.each :

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

4
Cảm ơn Tim, sử dụng gạch dưới nên chắc chắn tốt để có một tùy chọn nhanh chóng và sạch sẽ.
Bộ giải mã

56

Nếu bạn sử dụng đệ quy, bạn có thể trả về các thuộc tính đối tượng ở bất kỳ độ sâu nào

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
Coi chừng các vòng lặp, như gọi nó trên nút DOM.
theazureshadow

45

Câu trả lời này là tổng hợp các giải pháp được cung cấp trong bài đăng này với một số phản hồi về hiệu suất . Tôi nghĩ có 2 trường hợp sử dụng và OP đã không đề cập nếu anh ta cần truy cập các khóa để sử dụng chúng trong quá trình lặp.

I. các phím cần được truy cập,

ofObject.keyscách tiếp cận

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

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

incách tiếp cận

let k;
for (k in obj) {

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

Sử dụng cái này một cách thận trọng, vì nó có thể in các thuộc tính nguyên mẫu của obj

✔ Cách tiếp cận ES7

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

}

Tuy nhiên, tại thời điểm chỉnh sửa, tôi không đề xuất phương pháp ES7, vì JavaScript khởi tạo rất nhiều biến trong nội bộ để xây dựng quy trình này (xem phản hồi để chứng minh). Trừ khi bạn không phát triển một ứng dụng khổng lồ đáng được tối ưu hóa, thì cũng không sao nhưng nếu tối ưu hóa là ưu tiên của bạn, bạn nên nghĩ về nó.

II. chúng ta chỉ cần truy cập từng giá trị,

ofObject.valuescách tiếp cận

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

}

Thêm phản hồi về các bài kiểm tra:

  • Bộ nhớ đệm Object.keyshoặc Object.valueshiệu suất là không đáng kể

Ví dụ,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Trong Object.valuestrường hợp, sử dụng forvòng lặp gốc với các biến được lưu trong bộ nhớ cache trong Firefox dường như nhanh hơn một chút so với sử dụng for...ofvòng lặp. Tuy nhiên, sự khác biệt không quan trọng lắm và Chrome đang chạy for...ofnhanh hơn forvòng lặp gốc , vì vậy tôi khuyên bạn nên sử dụng for...ofkhi xử lý Object.valuestrong mọi trường hợp (thử nghiệm thứ 4 và thứ 6).

  • Trong Firefox, for...invòng lặp rất chậm, vì vậy khi chúng ta muốn lưu trữ khóa trong quá trình lặp thì tốt hơn là sử dụng Object.keys. Cộng với Chrome đang chạy cả hai cấu trúc ở tốc độ như nhau (thử nghiệm đầu tiên và thử nghiệm cuối cùng).

Bạn có thể kiểm tra các bài kiểm tra tại đây: https://jsperf.com/es7-and-misc-loops


2
Ví dụ ES7 hoạt động như một cơ duyên với React Native!
Ty Bailey

Giải thích một cách độc đáo. Cảm ơn
Alok Ranjan

30

Tôi biết rằng đã đến trễ, nhưng tôi đã mất 2 phút để viết phiên bản cải tiến và tối ưu hóa này của câu trả lời của 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]);
            }

        }

    }

}

1
Tại sao các bạn lưu trữ hasOwnPropertytrong ownsvà sau đó kêu gọi owns.call(obj, prop)thay vì chỉ gọi obj.hasOwnProperty(prop)câu trả lời này không?
Rory O'Kane

14
Bởi vì objcó thể có hasOwnPropertychức năng tự xác định nên nó sẽ không sử dụng chức năng từ đó Object.prototype. Bạn có thể thử trước forvòng lặp như thế này obj.hasOwnProperty = function(){return false;}và nó sẽ không lặp lại trên bất kỳ thuộc tính nào.
Azder

4
@Azder +1 cho câu trả lời và +1 nếu tôi có thể làm điều tốt đẹp về Object.prototype.hasOwnProperty. Tôi đã thấy rằng trước đây bên trong mã nguồn của thư viện gạch dưới nhưng không biết tại sao.
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 là giá trị

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

HOẶC LÀ

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

9

Trong ES7 bạn có thể làm:

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

Tôi đã thực hiện một số thử nghiệm, phương pháp này thực sự chậm khi xử lý lượng dữ liệu lớn.
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

Vài cách để làm điều đó ...

1) 2 lớp cho ... trong vòng lặp ...

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

2) Sử dụngObject.key

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

3) Hàm đệ quy

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

Và gọi nó như:

recursiveObj(validation_messages);

5

Ở đây có phiên bản cải tiến và đệ quy của giải pháp AgileJon ( bản 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);

Giải pháp này hoạt động cho tất cả các loại độ sâu khác nhau.


5

Một lựa chọn khác:

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

Tôi đã thử giải pháp của bạn trong Chrome 55.0 và bạn gặp lỗi loại. Câu trả lời của bạn có vẻ hay và cô đọng, nếu bạn có thể làm cho nó hoạt động thì có lẽ đó là một trong những lựa chọn tốt hơn. Tôi đã cố gắng tìm hiểu nó nhưng không hiểu giải pháp của bạn.
TolMera

2
@TolMera Đã sửa.
anh chàng

4

ECMAScript-2017, vừa hoàn thành một tháng trước, giới thiệu Object.values ​​(). Vì vậy, bây giờ bạn có thể làm điều này:

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

3

Tôi nghĩ rằng đáng để chỉ ra rằng jQuery sắp xếp thứ này độc đáo $.each().

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

Ví dụ:

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

$(this)là vật phẩm duy nhất bên trong đối tượng. Hoán đổi $('.foo')một biến nếu bạn không muốn sử dụng công cụ chọn của jQuery.


3

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

Để lặp qua Đối tượng JavaScript, chúng ta có thể sử dụng forEach và để tối ưu hóa mã, chúng ta có thể sử dụng chức năng mũi tên


2

Tôi không thể có được những bài viết trên để làm tốt những gì tôi đã làm sau đó.

Sau khi chơi xung quanh với các câu trả lời khác ở đây, tôi đã thực hiện điều này. Đó là hacky, nhưng nó hoạt động!

Đối với đối tượng này:

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

... mã này:

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

... Sản xuất cái này trong bảng điều khiển:

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

0

Giải pháp phù hợp với tôi là như sau

_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

Kỳ lạ - vượt qua sâu

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

  // ... your code

  return value;
})

Trong giải pháp này, chúng tôi sử dụng trình thay thế cho phép di chuyển sâu toàn bộ đối tượng và các đối tượng lồng nhau - ở mỗi cấp độ, bạn sẽ nhận được tất cả các trường và giá trị. Nếu bạn cần có được đường dẫn đầy đủ đến từng lĩnh vực, hãy nhìn vào đây


-6

Trong trường hợp của tôi (trên cơ sở trước đó) có thể có bất kỳ số lượng cấp độ.

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

kết quả:

["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"]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.