如何遍历JavaScript对象?


422

我在JavaScript中有一个对象:

{
    abc: '...',
    bca: '...',
    zzz: '...',
    xxx: '...',
    ccc: '...',
    // ...
}

我想使用一个for循环来获取其属性。而且我想对其进行迭代(不是一次所有对象属性)。

通过一个简单的数组,我可以使用标准for循环来做到这一点:

for (i = 0; i < 100; i++) { ... } // first part
for (i = 100; i < 300; i++) { ... } // second
for (i = 300; i < arr.length; i++) { ... } // last

但是如何处理对象呢?


22
请记住,对象属性不是按顺序存储的。当您遍历一个对象时,并不能保证它们出现的顺序。
James Allardice

Answers:


850

对于大多数对象,请使用for .. in

for (let key in yourobject) {
  console.log(key, yourobject[key]);
}

使用ES6,如果同时需要键和值,请执行

for (let [key, value] of Object.entries(yourobject)) {
    console.log(key, value);
}

为了避免记录继承的属性,请使用hasOwnProperty进行检查:

for (let key in yourobject) {
   if (yourobject.hasOwnProperty(key)) {
      console.log(key, yourobject[key]);
   }
}

hasOwnProperty如果您使用的是简单对象(例如,您自己创建的对象),则无需在迭代键时进行检查{}

该MDN文档更一般地说明了如何处理对象及其属性。

如果要“分块”执行,最好的方法是将键提取到数组中。由于不能保证顺序,这是正确的方法。在现代浏览器中,您可以使用

let keys = Object.keys(yourobject);

为了更加兼容,您最好这样做:

 let keys = [];
 for (let key in yourobject) {      
     if (yourobject.hasOwnProperty(key)) keys.push(key);
 }

然后,您可以按索引访问属性yourobject[keys[i]]

for (let i=300; i < keys.length && i < 600; i++) { 
   console.log(keys[i], yourobject[keys[i]]);
}

3
OP希望分块执行此操作,而不是在单个循环中执行所有键。
pawel 2013年

是。一个循环中没有完整的对象。
nkuhta 2013年

2
@Cerbrus OP已经准备好了如何迭代部分数组。keys从给定的代码使用就足够了。
Yoshi

2
@Cerbrus请在评论前阅读!什么是不以明文“更兼容的,你最好这样做”
DenysSéguret13年

2
@ am05mhz如我所说,它对大多数对象都没有用。但不是所有人。试试这个:jsbin.com/hirivubuta/1/edit?js,console,output
DenysSéguret15年

61

这是现代浏览器的另一个迭代解决方案:

Object.keys(obj)
  .filter((k, i) => i >= 100 && i < 300)
  .forEach(k => console.log(obj[k]));

或不带过滤功能:

Object.keys(obj).forEach((k, i) => {
    if (i >= 100 && i < 300) {
        console.log(obj[k]);
    }
});

但是,您必须考虑JavaScript对象中的属性未排序,即没有顺序。


如果我要中断循环,它将在下一次从对象的开头开始,这不是正确的方法。
nkuhta 2013年

21

Object.entries你做这样的事情。

 // array like object with random key ordering
 const anObj = { 100: 'a', 2: 'b', 7: 'c' };
 console.log(Object.entries(anObj)); // [ ['2', 'b'],['7', 'c'],['100', 'a'] ]

Object.entries()方法返回给定对象自己的可枚举属性[key,value]的数组

所以,你可以遍历对象,并有keyvalue每个对象,并得到这样的事情。

const anObj = { 100: 'a', 2: 'b', 7: 'c' };
Object.entries(anObj).map(obj => {
   const key   = obj[0];
   const value = obj[1];

   // do whatever you want with those values.
});

或像这样

// Or, using array extras
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

作为参考,请查看对象条目的MDN文档


17

借助新的ES6 / ES2015功能,您不再需要使用对象来遍历哈希。您可以使用地图。Javascript Maps将键按插入顺序保留,这意味着您可以遍历它们而不必检查hasOwnProperty,这始终是一个hack。

遍历地图:

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

for (var key of myMap.keys()) {
  console.log(key);
}
// Will show 2 logs; first with "0" and second with "1"

for (var value of myMap.values()) {
  console.log(value);
}
// Will show 2 logs; first with "zero" and second with "one"

for (var [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

或使用forEach:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

1
forEach是每个人的首选
pungggi

14

如果在迭代时需要键和值,则可以Object.entries使用for ... of循环。

const myObj = {a: 1, b: 2}

for (let [key, value] of Object.entries(myObj)) {
    console.log(`key=${key} value=${value}`)
}

// output: 
// key=a value=1
// key=b value=2

7

唯一可靠的方法是将对象数据保存到2个数组中,其中之一是键,另一个用于数据:

var keys = [];
var data = [];
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        keys.push(key);
        data.push(obj[key]); // Not necessary, but cleaner, in my opinion. See the example below.
    }
}

然后,您可以像通常那样遍历数组:

for(var i = 0; i < 100; i++){
    console.log(keys[i], data[i]);
    //or
    console.log(keys[i], obj[keys[i]]); // harder to read, I think.
}
for(var i = 100; i < 300; i++){
    console.log(keys[i], data[i]);
}

我没有使用Object.keys(obj),因为那是IE 9+。


3

->如果我们使用遍历一个JavaScript对象并找到对象数组的键

Object.keys(Array).forEach(key => {

 console.log('key',key)

})

1

如果您想一次迭代整个对象,可以使用for in循环:

for (var i in obj) {
  ...
}

但是,实际上,如果您要将对象分成几部分,就不能这样做。不能保证对象中的属性以任何指定的顺序进行。因此,我可以想到两种解决方案。

首先是“删除”已读取的属性:

var i = 0;
for (var key in obj) {
    console.log(obj[key]);
    delete obj[key];
    if ( ++i > 300) break;
}

我能想到的另一种解决方案是使用数组而不是对象:

var obj = [['key1', 'value1'], ['key2', 'value2']];

然后,标准for循环将起作用。



1

您可以尝试使用lodash-一个现代的JavaScript实用程序库,可提供模块化,性能和Extras js来快速进行对象迭代:-

var  users  =   {
    'fred':     { 
        'user':   'fred',
            'age':  40 
    },
    'pebbles':  { 
        'user':   'pebbles',
         'age':  1 
    }
}; 
_.mapValues(users,  function(o)  { 
    return  o.age; 
});
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
// The `_.property` iteratee shorthand.
console.log(_.mapValues(users,  'age')); // returns age property & value 
console.log(_.mapValues(users,  'user')); // returns user property & value 
console.log(_.mapValues(users)); // returns all objects 
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.js"></script>


1

对于对象迭代,我们通常使用for..in循环。此结构将遍历所有可枚举的属性,包括通过原型继承继承的属性。例如:

let obj = {
  prop1: '1',
  prop2: '2'
}

for(let el in obj) {
  console.log(el);
  console.log(obj[el]);
}

但是,for..in它将遍历所有可枚举的元素,这将使我们无法将迭代拆分为多个块。为此,我们可以使用内置Object.keys()函数来检索数组中对象的所有键。然后,我们可以将迭代拆分为多个for循环,并使用keys数组访问属性。例如:

let obj = {
  prop1: '1',
  prop2: '2',
  prop3: '3',
  prop4: '4',
};

const keys = Object.keys(obj);
console.log(keys);


for (let i = 0; i < 2; i++) {
  console.log(obj[keys[i]]);
}


for (let i = 2; i < 4; i++) {
  console.log(obj[keys[i]]);
}


0
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);

1
其实不行 这意味着Objects是有序的。他们不是。If you can make sense of the sentence it worked仅由于实现细节而起作用。根本不能保证它能正常工作。另外,您不应该在TitleCase中使用函数和变量。那是给classes的。
Florian Wendelborn

0

确实是PITA,这不是标准Javascript的一部分。

/**
 * Iterates the keys and values of an object.  Object.keys is used to extract the keys.
 * @param object The object to iterate
 * @param fn (value,key)=>{}
 */
function objectForEach(object, fn) {
    Object.keys(object).forEach(key => {
        fn(object[key],key, object)
    })
}

注意:我将回调参数切换为(value,key),并添加了第三个对象以使该API与其他API一致。

这样使用

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});

1
只为您在第一句话中的发言投票支持。即使值最好是第一个参数,索引或键的第二个参数以及对象的第三个参数,也可以使其更像数组forEach()。我建议还是推荐lodash。
合同说的没错,2018年

我确实喜欢(值,键)顺序的想法。这就是Vue这样的库也是这样做的。由于对象是上下文,因此它确实认为它属于第一个参数。这是函数式编程的相当标准。
史蒂文·斯潘金

如果不是ECMA-262将数组定义为具有forEach(),map(),reduce(),filter()的对象,这些对象都接受接收顺序[值,索引,数组]的回调,我在这里会同意。JS中的对象可以理解为另一个集合。然后这些方法在[值,键|索引,上下文]的参数中变得统一(这是lodash和下划线所做的)。我认为,这种“统一收集”协议更加强大。同样,对象也不是上下文:您可以this为回调设置任意值,因为回调具有自己的上下文。
合同说我没错,2018年

也许我应该用工作接收器代替它。无论如何仍然是PITA;我会以任何顺序欢迎这些参数。
史蒂文·斯潘金

哦,我知道我们可能互相误解了。我一直在评论回调参数及其顺序,而不是实际objectForEach功能。抱歉,这令人困惑。
合同说我没错,2018年

0

是。您可以使用for循环遍历对象。这是一个例子

var myObj = {
    abc: 'ABC',
    bca: 'BCA',
    zzz: 'ZZZ',
    xxx: 'XXX',
    ccc: 'CCC',
}

var k = Object.keys (myObj);
for (var i = 0; i < k.length; i++) {
    console.log (k[i] + ": " + myObj[k[i]]);
}

注意:上述示例仅在IE9 +中有效。请参阅此处的 Objec.keys浏览器支持。


0
const o = {
  name: "Max",
  location: "London"
};

for (const [key, value] of Object.entries(o)) {
  console.log(`${key}: ${value}`);
}

在线尝试

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.