如何使用对象作为成员循环一个普通的JavaScript对象?

edt*_*edt 1521 javascript

如何遍历JavaScript对象中的所有成员,包括作为对象的值.

例如,我怎么能循环这个(访问每个的"your_name"和"your_message")?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}
Run Code Online (Sandbox Code Playgroud)

Agi*_*Jon 2056

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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你正在使用jQuery,$ .each()/ do /在IE中工作. (37认同)
  • 当您执行obj [prop]时,Internet Explorer不同意(*叹*),说"对象不支持此属性或方法".我还没有找到解决方案. (12认同)
  • for ... in是一个很好的解决方案,但如果你在for()循环中使用promises要小心,因为如果你在循环中创建一个var,你就不能在promise' then-function中使用它.你在循环中的var只存在一次,所以它在每个then-function中都有相同的,甚至是最后一个值.如果您有这个问题,请尝试"Object.keys(obj).forEach"或我的答案如下. (4认同)
  • @MildFuzz实际上如果你认为JS对象不需要数字键是有意义的.你不能只是遍历一个对象.JS的'for in`非常类似于传统的`foreach`. (2认同)

Axe*_*yer 726

在ECMAScript中5,你可以结合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]);

});
Run Code Online (Sandbox Code Playgroud)

  • +1代码的简洁,但显然,效果不如出人意料.[JSPerf - for in vs Object.keys](http://jsperf.com/objdir) (29认同)
  • 使用这种方法注意这个错误:"TypeError:在非对象上调用Object.keys".在我可以告诉的任何东西上都可以调用`for ... in ... hasOwnProperty`模式(对象,数组,空,未定义,真,假,数字原语,对象). (6认同)
  • @ techiev2:它不是`Object.keys()`,它使它变慢,它更像是`forEach()`和重复访问`.length`!如果你使用经典的`for`循环,它几乎是Firefox 33中`for..in` +`hasOwnProperty()`的两倍. (4认同)
  • @techiev2 一点也不奇怪,Axel Rauschmayer 的方法使用`keys` 函数和`forEach` 函数,它需要解析匿名函数,然后在forEach 循环的每个元素上调用匿名函数。如果您了解编程,您就会明白所有这些解析和函数调用比原生解决方案(如 for 结构循环)花费的时间要多得多。 (3认同)
  • 请注意,IE7不支持此功能. (2认同)
  • @ techiev2那些测试从未有效.有关当前的性能状态,请参阅我的更新内容:http://jsperf.com/objdir/20 (2认同)
  • Object.keys(obj).reduce((p,c)=> p.concat(obj[c]),[]) (2认同)
  • 似乎[这是现在唯一推荐的jslint`for`循环](http://stackoverflow.com/a/30518734/274502)。来自站点的帮助:_“JSLint 不建议使用 `for` 语句。改用像 `forEach` 这样的数组方法。JSLint 不建议使用 `for in` 语句。改用 `Object.keys`。” _ (2认同)
  • 如果你在反应,你可能想使用 `.map()` 而不是 `.forEach()` /sf/ask/2797590561/ (2认同)

Cha*_*ngo 381

这个问题

for (var key in validation_messages) {
   var obj = validation_messages[key];
   for (var prop in obj) {
      alert(prop + " = " + obj[prop]);
   }
}
Run Code Online (Sandbox Code Playgroud)

是你还将循环原始对象的原型.

有了这个,你会避免它:

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]);
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,仅当您的对象具有原型方法时才需要这样做.例如,如果您循环的对象只是一个JSON对象,则不需要进行此检查. (58认同)
  • 简而言之:在`for`-`in`循环中检查[`hasOwnProperty`](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty). (46认同)
  • @rednaw为了安全起见,我使用该检查,因为可以修改Object.prototype.没有理智的脚本可以做到这一点,但是您无法通过疯狂的浏览器扩展来控制页面中可能运行的脚本.浏览器扩展在您的页面中运行(在大多数浏览器上)并且它们可能导致奇怪的问题(例如,将window.setTimeout设置为null!). (6认同)

Rot*_*eti 274

ES6中,您可以循环遍历这样的对象:(使用箭头功能)

Object.keys(myObj).forEach(key => {
  console.log(key);        // the name of the current key.
  console.log(myObj[key]); // the value of the current key.
});
Run Code Online (Sandbox Code Playgroud)

jsbin

ES7中,你可以使用Object.entries代替Object.keys和循环遍历这样的对象:

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

以上也可以作为一个单行:

Object.entries(myObj).forEach(([key, val]) => console.log(key, val));
Run Code Online (Sandbox Code Playgroud)

jsbin

如果您想循环遍历嵌套对象,可以使用递归函数(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.
  });
};
Run Code Online (Sandbox Code Playgroud)

jsbin

与上面的功能相同,但使用ES7 Object.entries()代替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.
  });
};
Run Code Online (Sandbox Code Playgroud)

如果您正在使用函数式编程,则可以使用Object.entries()/ Object.fromEntries()枚举对象,然后处理这些值,然后使用Object.entries它们转换回新对象.

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.
    })
  );
Run Code Online (Sandbox Code Playgroud)

  • 我认为添加一个事实是有用的,即Object.entries和Object.keys不会遍历原型,这是它与for in构造之间的巨大差异. (5认同)
  • 对于使用Object.entries示例的ES7,需要在括号中包含箭头函数参数[key,val],如:`Object.entries(myObj).forEach(([key,val])=> {/*statements*/} (2认同)

Tim*_*ord 94

使用Underscore.js_.each:

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});
Run Code Online (Sandbox Code Playgroud)

  • 谢谢蒂姆,使用下划线非常好,有一个快速和干净的选择. (4认同)

ken*_*bec 55

如果使用递归,则可以返回任何深度的对象属性 -

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
}

*/
Run Code Online (Sandbox Code Playgroud)

  • 注意循环,比如在DOM节点上调用它. (2认同)

vde*_*nne 39

这个答案是本文中提供的一些性能反馈解决方案的汇总.我认为有2个用例,OP没有提到他是否需要访问密钥以便在循环过程中使用它们.

I.需要访问密钥,

ofObject.keys方法

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

    /*        k : key
     *   obj[k] : value
     */
}
Run Code Online (Sandbox Code Playgroud)

in方法

let k;
for (k in obj) {

    /*        k : key
     *   obj[k] : value
     */
}
Run Code Online (Sandbox Code Playgroud)

谨慎使用这个,因为它可以打印原型的属性 obj

✔ES7方法

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

}
Run Code Online (Sandbox Code Playgroud)

但是,在编辑时我不建议使用ES7方法,因为JavaScript在内部初始化了很多变量来构建此过程(请参阅反馈以获取证明).除非你没有开发一个值得优化的巨大应用程序,否则它是可以的,但如果优化是你的首要任务,你应该考虑一下.

II.我们只需要访问每个值,

ofObject.values方法

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

}
Run Code Online (Sandbox Code Playgroud)

有关测试的更多反馈:

  • 缓存Object.keysObject.values性能可以忽略不计

例如,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
Run Code Online (Sandbox Code Playgroud)
  • 例如Object.values,for在Firefox中使用带有缓存变量的本机循环似乎比使用for...of循环要快一些.然而,差异并不重要,Chrome运行for...of速度比原生for循环快,所以我建议在任何情况下for...of处理时使用Object.values(第4和第6次测试).

  • 在Firefox中,for...in循环非常慢,因此当我们想要在迭代期间缓存密钥时,最好使用Object.keys.此外,Chrome以相同的速度运行两种结构(第一次和最后一次测试).

您可以在此处查看测试:https: //jsperf.com/es7-and-misc-loops

  • ES7示例在React Native上的魅力十足! (2认同)

Azd*_*der 29

我知道这已经很晚了,但是我花了2分钟来编写这个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]);
            }

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

  • 因为`obj`可能会自定义`hasOwnProperty`函数,所以它不会使用`Object.prototype`中的函数.您可以在`for`循环之前尝试这样的`obj.hasOwnProperty = function(){return false;}`并且它不会迭代任何属性. (13认同)
  • @Azder +1答案和+1,如果我可以为Object.prototype.hasOwnProperty的好事.我之前在下划线库的源代码中看到过,但不知道为什么. (4认同)
  • 为什么你将 `hasOwnProperty` 存储在 `owns` 中,然后调用 `owns.call(obj, prop)` 而不是仅仅调用 `obj.hasOwnProperty(prop)` 作为 [this answer](http://stackoverflow.com/ a/2869372/578288)呢? (2认同)

cha*_*aos 28

for(var k in validation_messages) {
    var o = validation_messages[k];
    do_something_with(o.your_name);
    do_something_else_with(o.your_msg);
}
Run Code Online (Sandbox Code Playgroud)


Wes*_*sam 12

p是值

for (var key in p) {
  alert(key + ' => ' + p[key]);
}
Run Code Online (Sandbox Code Playgroud)

要么

Object.keys(p).forEach(key => { console.log(key, p[key]) })
Run Code Online (Sandbox Code Playgroud)


Kév*_*ier 9

在ES7中,您可以:

for (const [key, value] of Object.entries(obj)) {
  //
}
Run Code Online (Sandbox Code Playgroud)


Dmi*_*kov 8

for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}
Run Code Online (Sandbox Code Playgroud)


Sou*_*rik 8

遍历对象的方法有很多种。请看下面的例子。

var obj = {'name':'John Doe','email':'johndoe@example.com'}
Run Code Online (Sandbox Code Playgroud)

方法一

var keys = Object.keys(obj)
for(var i= 0; i < keys.length;i++){
  console.log(keys[i]+ ': ' + obj[keys[i]])
}
Run Code Online (Sandbox Code Playgroud)

方法2

for(var key in obj){
  console.log(key+': '+ obj[key])
}
Run Code Online (Sandbox Code Playgroud)

方法3

Object.keys(obj).forEach(function (key) {
  console.log(key+ ': ' + obj[key])
})
Run Code Online (Sandbox Code Playgroud)


dud*_*ude 6

另外一个选项:

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


Ali*_*eza 6

很少有这样做的方法...

1) 2层...在循环中...

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

2)使用Object.key

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

3)递归函数

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]);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

并这样称呼:

recursiveObj(validation_messages);
Run Code Online (Sandbox Code Playgroud)


Jep*_*epZ 5

这是AgileJon解决方案(演示)的改进和递归版本:

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);
Run Code Online (Sandbox Code Playgroud)

该解决方案适用于各种不同的深度.


Cho*_*ang 5

一个月前刚刚完成的ECMAScript 2017引入了 Object.values()。所以现在你可以这样做:

let v;
for (v of Object.values(validation_messages))
   console.log(v.your_name);   // jimmy billy
Run Code Online (Sandbox Code Playgroud)