遍历对象属性


2037

var obj = {
    name: "Simon",
    age: "20",
    clothing: {
        style: "simple",
        hipster: false
    }
}

for(var propt in obj){
    console.log(propt + ': ' + obj[propt]);
}

变量如何propt表示对象的属性?它不是内置方法或属性。为什么它包含对象中的每个属性?


11
if (typeof(obj[propt]) === 'object') {/ *再做一次* /}
noob

13
好吧,真的很抱歉这个问题。我知道循环是什么,我无法绕过“循环遍历对象属性”,我认为现在已经清除了。此外,他们还向我推荐“的JavaScript分步第2版-史蒂夫Suehring在学校。
Rafay

242
这是一个很好的初学者问题。我还要补充说,我有15年其他语言的专业经验,所以我需要这个答案。如果可以的话,我会加2000。
内森·T·雷施

60
太疯狂了,但是多年来,我每隔几个月都会访问此页面,以重新学习如何执行此操作的语法。我不介意记住该怎么做...我只记得该页面始终在SO上。
HDave 2015年

14
这是我在StackOverflow上看到的最奇怪的页面。如果您仔细阅读了该问题,则甚至只有一个答案开始尝试回答实际要问的问题,并且它的得分为-6。得分最高的答案被接受,不仅没有答案,而且完全是错误的。

Answers:


2424

遍历属性需要以下附加hasOwnProperty检查:

for (var prop in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        // do stuff
    }
}

这是必需的,因为对象的原型包含该对象的其他属性,这些属性在技术上是对象的一部分。这些附加属性是从基础对象类继承的,但仍然是的属性obj

hasOwnProperty 只需检查一下这是否是该类的特定属性,而不是从基类继承的属性。


也可以hasOwnProperty通过对象本身进行调用:

if (obj.hasOwnProperty(prop)) {
    // do stuff
}

但这将失败,如果对象具有一个不相关的同名字段:

var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo');  // TypeError: hasOwnProperty is not a function

这就是为什么更安全地调用它的原因Object.prototype

var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo');  // true

21
@BT根据Mozilla文档:“如果只想考虑对象本身的属性,而不是对象的原型,请使用getOwnPropertyNames 或执行hasOwnProperty检查(也可以使用propertyIsEnumerable)。”
davidmdem

3
通话的目的到底是什么object.hasOwnProperty()property具有任何价值的事实是否暗示着它的存在object
Alex S

6
因为,Alex S,对象的原型包含该对象的其他属性,这些属性在技术上是对象的一部分。它们是从基础对象类继承的,但是它们仍然是属性。hasOwnProperty仅检查该属性是否是该类的特定属性,而不是从基类继承的属性。一个很好的解释:brianflove.com/2013/09/05/javascripts-hasownproperty-method
Kyle Richter

87
我觉得应该提一下,不过Object.keys(obj)现在是获取对象本身的键的更好的解决方案。链接到Mozilla的文档:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
凯尔里氏

9
一个重要的信息丢失了。property是一个字符串,应调用propertyName。否则可能会使像我这样的JS新手感到困惑,即在里面做什么if
Neolisk '16

1135

从JavaScript 1.8.5开始,您可以Object.keys(obj)用来获取在对象本身上定义的属性数组(为返回true的属性obj.hasOwnProperty(key))。

Object.keys(obj).forEach(function(key,index) {
    // key: the name of the object key
    // index: the ordinal position of the key within the object 
});

这比使用for-in循环更好(更易读)。

这些浏览器支持它:

  • Firefox(壁虎):4(2.0)
  • 铬:5
  • Internet Explorer:9

有关更多信息,请参见Mozilla开发人员网络Object.keys()的参考



3
如果你需要对旧的浏览器的支持,您可以使用该填充工具
KyleMit

27
在支持此语言构造的环境中,此方法允许调用Array.foreach:Object.keys(myObject).forEach(function(key,index) { //key = the name of the object key //index = the ordinal position of the key within the object });
Todd Price

4
@ AJ_83没有打破forEach()的好方法。在这种情况下使用some(),并返回true即可中断
Daniel Z.

11
为什么比for-in更具可读性?for candidate in candidateStatus...对我来说似乎可读
乔纳(Jona)

308

我们现在处于2019年的男女生中,我们没有太多的时间来打字...所以,让我们来做一下这个酷炫的新奇ECMAScript 2016:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));

17
这与Danny R的答案有何不同?
krillgar

27
它是一个单行,并且使用map代替forEach。而且console.log的使用对于某些人来说可能很有趣。
Frank Roth

遗憾的是,当obj=window.performance.memory:-/在哪里时,for in它不起作用。即var obj = window.performance.memory; for( key in obj ) console.log( 'key=' + key + ' val=' + obj[key] );
Michaelangel007'2

2
window.performance.memory仅受chrome支持,并Object.keys(obj)返回一个空数组。这与无关.map
弗兰克·罗斯

如果有人不想四处乱逛地重组e这种单缸纸,一次只做一件事情,我已经发布了这个要点。它基本上与大多数散列实现一样,并且使用( (key) => (value) )代替{ key => value },但是如果您以前没有处理过,它可以帮助您更好地可视化它:gist.github.com/the-nose-knows/9f06e745a56ff20519707433e28a4fa8
kayleeFrye_onDeck

216

这是for...in statementMDNECMAScript spec)。

你可以把它读作“ FOR每个属性INobj对象,每个属性分配给PROPT依次变量”。


1
非常感谢,我现在明白了。我正在头,浏览书籍和Google。
拉斐

21
与@RightSaidFred,在同意in经营者和for未参与在所有的说法,for-in声明表示对自己的文法产生:for ( LeftHandSideExpression in Expression )for ( var VariableDeclarationNoIn in Expression )
CMS

2
奇怪的是,这个答案获得了很高的好评,尤其是因为这些流行的评论似乎与之矛盾。
Doug Molineux

9
为什么将此标记为答案?这很可能是至少有帮助的人在这个线程..
computrius

3
最少有用的答案?取决于您对OP的要求;当我第一次阅读该问题时,对于变量可用于检查对象属性的机制似乎感到困惑不解,并且这个答案雄辩地说明了这一点(尽管“用词不当”)。这个问题:“为什么会拿出所有的财产”我看可能意味着OP一直在寻找hasOwnProperty,但不知道它,但我认为它更可能是OP想知道什么,并且错误地接受了正确的回答另一个问题。:-)
Bumpy

157

在ES的最新实现中,您可以使用Object.entries

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

要么

Object.entries(obj).forEach(([key, value]) => ...)

如果只想遍历值,请使用Object.values:

for (const value of Object.values(obj)) { }

要么

Object.values(obj).forEach(value => ...)

这将是最好的解决方案(object.entries ...),但是我不能使用它。当你想这个多次做并不能支持它在你的框架,您可以用填充工具在此页上:developer.mozilla.org/nl/docs/Web/JavaScript/Reference/...
马里奥

如果您仅选择属性值,那么第三条建议是很棒的。太棒了!
Ginzburg


27

如果您的环境支持ES2017,那么我建议使用Object.entries

Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`);
});

Mozillas Object.entries()文档所示:

所述Object.entries()方法返回在给定对象的自己的可枚举的属性[键,值]对的数组,在相同的顺序,通过提供一种用于... in循环(不同之处在于一个用于-in循环枚举原型链中的属性)。

基本上使用Object.entries,我们可以放弃旧的for ... in循环所需的以下额外步骤:

// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}

22

jQuery允许您立即执行此操作:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});

1
$.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)})$ .each 不适合对象。如果一个对象恰好具有length属性并且其值恰好为零,则将整个对象视为空数组。
鲍勃·斯坦

详细说明为什么我认为这是诱人的方法
鲍勃·斯坦

21

Dominik的答案很完美,我只喜欢那样做,因为它更容易阅读:

for (var property in object) {
    if (!object.hasOwnProperty(property)) continue;

    // Do stuff...
}

不过应该是Object大写的吗?
乔纳森

18

上面的答案有点烦人,因为在您确定它是一个对象之后,它们并没有解释您在for循环内所做的事情:您不会直接访问它!实际上,您仅交付了需要应用于OBJ的密钥:

var obj = {
  a: "foo",
  b: "bar",
  c: "foobar"
};

// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
  // We check if this key exists in the obj
  if (obj.hasOwnProperty(someKey))
  {
    // someKey is only the KEY (string)! Use it to get the obj:
    var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"

    // NOW you can treat it like an obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

这都是ECMA5安全的。甚至可以在像Rhino这样the脚的JS版本中工作;)


15

添加ES2015的用法,Reflect.ownKeys(obj)并通过迭代器对属性进行迭代。

例如:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

可以被迭代

// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

如果您想直接遍历对象键的值,则可以定义一个 iterator,就像JavaScipts的字符串,数组,类型数组,Map和Set的默认迭代器一样。

JS将尝试通过默认的迭代器属性进行迭代,该属性必须定义为Symbol.iterator

如果您希望能够遍历所有对象,则可以将其添加为Object的原型:

Object.prototype[Symbol.iterator] = function*() { 
    for(p of Reflect.ownKeys(this)){ yield this[p]; }
}

这将使您能够使用for ... of循环遍历对象的值,例如:

for(val of obj) { console.log('Value is:' + val ) }

注意:截至撰写此答案(2018年6月)时,所有其他浏览器均支持此功能,但IE支持for...of通过以下方式生成器和进行迭代Symbol.iterator


尽管您实际上没有回答OP的问题,但这对我很有帮助,我还不了解Reflect。
米歇尔

15
if(Object.keys(obj).length) {
    Object.keys(obj).forEach(key => {
        console.log("\n" + key + ": " + obj[key]);
    });
}

// *** Explanation line by line ***

// Explaining the bellow line
// It checks if obj has at least one property. Here is how:
// Object.keys(obj) will return an array with all keys in obj
// If there is no keys in obj, it will return empty array = []
// Then it will get it's length, if it has at least one element,
// it's bigger than 0 which evaluates to true and the bellow 
// code will be executed.
// Else means it's length = 0 which evaluates to false
// NOTE: you can use Object.hasOwnProperty() instead of Object.keys(obj).length
if(Object.keys(obj).length) {

    // Explaining the bellow line
    // Just like in the previous line, this returns an array with
    // all keys in obj (because if code execution got here, it means 
    // obj has keys.) 
    // Then just invoke built-in javascript forEach() to loop
    // over each key in returned array and calls a call back function 
    // on each array element (key), using ES6 arrow function (=>)
    // Or you can just use a normal function ((key) { blah blah }).
    Object.keys(obj).forEach(key => {

        // The bellow line prints out all keys with their 
        // respective value in obj.
        // key comes from the returned array in Object.keys(obj)
        // obj[key] returns the value of key in obj
        console.log("\n" + key + ": " + obj[key]);
    });
}

3
嗨,您能否添加有关答案的更多信息,仅提供代码无济于事。
尼古拉斯

嗨,@ Nicolas,我在代码中一行一行地添加了解释。让我知道是否仍然不清楚
Fouad Boukredine

因为forEach 跳过空值,所以我认为您可以摆脱if,而只需执行Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));Frank Roth的答案即可。
Darkproduct

12

for ... in循环表示对象中的每个属性,因为它就像for循环一样。您通过执行以下操作在for ... in循环中定义了propt:

    for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}

for ... in循环遍历对象的可枚举属性。无论您定义哪个变量或将其放入for ... in循环中,每次转到下一个迭代的属性时,该变量都会更改。for ... in循环中的变量遍历键,但是它的值是键的值。例如:

    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs "Simon"
    }

您可以看到变量与变量值的不同之处。相反,for ... of循环则相反。

我希望这有帮助。


11
let obj = {"a": 3, "b": 2, "6": "a"}

Object.keys(obj).map((item) => {console.log("item", obj[item])})

// a
// 3
// 2

1
如其他注释中所述,forEach此处更合适,因为map它旨在返回一个新数组,并在每次迭代时调用代码块。但是我们只关注每次迭代的副作用,而不关注返回值,因此我们不需要map给我们的新数组。
丹尼

11
Object.keys(obj).forEach(key =>
  console.log(`key=${key} value=${obj[key]}`)
);

10

您可以使用Lodash。该文件

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});

10
为什么这个“答案”有10个投票?它完全无法回答这个问题。我开始对普通JS开发人员的智力失去信心。
developerbmw

1
@developerbmw我知道使用ES6功能是更正确的方法,但是我在一年前已经回答过。请在有空的时候与我们分享您的想法。
viktarpunko

1
这个想法是将更多精力放在本机方法上,而不是建议用户向其页面添加10000行库。不要误会我的意思,我确实喜欢使用Lodash,但是确实有一个时间和一个地方,而这不是。

9

您的for循环正在遍历对象的所有属性objpropt在for循环的第一行中定义。它是一个字符串,它是obj对象属性的名称。在循环的第一次迭代中,propt将为“名称”。


9

JavaScript中的对象是属性的集合,因此可以在每个语句的a中循环。

您应该将其obj视为键值集合。


!重要的区别在于这些“属性列表”可以将名称作为键,而普通的JS数组只能将数字作为键。
2011年

9

现在,您只需添加Symbol.iterator方法就可以将标准JS对象转换为可迭代对象。然后,您可以使用for of循环并直接使用其值,甚至还可以在对象上使用散布运算符。凉。让我们看看如何做到这一点:

var o = {a:1,b:2,c:3},
    a = [];
o[Symbol.iterator] = function*(){
                       var ok = Object.keys(this);
                            i = 0;
                       while (i < ok.length) yield this[ok[i++]];
                     };
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);


1
有趣的方式做到这一点。感谢您的function*发现!

5

如果运行节点,我建议:

Object.keys(obj).forEach((key, index) => {
    console.log(key);
});

5

虽然最受好评的答案是正确的,但这是一个替代用例,即如果您要遍历一个对象并想最后创建一个数组。使用.map代替forEach

const newObj = Object.keys(obj).map(el => {
    //ell will hold keys 
   // Getting the value of the keys should be as simple as obj[el]
})

4

还添加了递归方法:

function iterate(obj) {
    // watch for objects we've already iterated so we won't end in endless cycle
    // for cases like var foo = {}; foo.bar = foo; iterate(foo);
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  // check if we haven't iterated through the reference yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

用法:

iterate({ foo: "foo", bar: { foo: "foo"} }); 

1
@faiz-请参阅我的评论,当您反复走动具有循环引用的槽对象时,这可以防止陷入无限循环
Ondrej Svejdar

3

for..in循环的作用是创建一个新变量(var someVariable),然后将给定对象的每个属性一一存储在此新变量(someVariable)中。因此,如果使用块{},则可以进行迭代。考虑以下示例。

var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet

考虑到它的简单性,支持这一点。在我的用例中,我需要检查对象中的所有属性是否存在闪闪发光的值-NaN,空值,未定义(它们是图形上的点,而这些值使图形无法绘制)。要获取值而不是名称,可以在循环中执行obj[someVariable]。它之所以被否决,可能是因为它不是递归的。因此,如果您具有高度结构化的对象,这将不是一个适当的解决方案。
凯瑟琳·奥斯本

@KatharineOsborne或可能是因为以下短语有点含糊:“因此,如果使用块{},则可以进行迭代。” 该代码不仅仅包含文本。
bvdb

3

在这里,我迭代每个节点并创建有意义的节点名称。如果您注意到,instanceOf Array和instanceOf Object几乎可以做同样的事情(在我的应用程序中,我给出了不同的逻辑)

function iterate(obj,parent_node) {
    parent_node = parent_node || '';
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            var node = parent_node + "/" + property;
            if(obj[property] instanceof Array) {
                //console.log('array: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            } else if(obj[property] instanceof Object){
                //console.log('Object: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            }
            else {
                console.log(node + ":" + obj[property]);
            }
        }
    }
}

注意-我受到Ondrej Svejdar的回答的启发。但是此解决方案具有更好的性能和更少的歧义


3

您基本上想遍历对象中的每个属性。

JSFiddle

var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);

obj(prop)<
-TypeError

@le_m,我不好。我必须不小心取出了hasOwnProperty属性。现在应该可以工作了。
HovyTech

2

我想补充上面的答案,因为您可能与Javascript有不同的意图。JSON对象和Javascript对象是不同的事物,您可能想使用上面提出的解决方案遍历JSON对象的属性,然后感到惊讶。

假设您有一个JSON对象,例如:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

遍历其“属性”的错误方法:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

遍历and 和of 的属性时0,您可能会惊讶地看到控制台日志记录1等。prop1prop2prop3_1。这些对象是序列,序列的索引是Javascript中该对象的属性。

递归遍历JSON对象属性的更好方法是首先检查该对象是否为序列:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }

     }
}

1

要进一步细化接受的答案值得一提的是,如果你实例化对象有var object = Object.create(null)那么object.hasOwnProperty(property)将触发类型错误。为了安全起见,您需要像这样从原型中调用它:

for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.