如何在JavaScript中循环或枚举一个对象?

3570
我有一个类似以下的 JavaScript 对象:
var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};
我如何循环遍历所有 p 元素 (p1p2p3...) 并获取它们的键和值?
48个回答

26

单行和更易读的代码可以通过使用链式方法来实现。

Object.entries(myObject).map(([key, value]) => console.log(key, value))

你的回答很好,比上面的解决方案更易读,但是你能解释一下在你的答案中 .map(([key, value]) 发生了什么吗? - Nivethan
1
@Nivethan,Object.entries 的输出将会是一个数组的数组。例如 [ ['key1', 'value'], ['key2', 'value'] ]。因此,map 方法将会循环遍历外层数组,并将每个数组元素一个接一个地传递到其回调函数中。所以,在这里我使用了数组解构语法([key, value]) => {},而不是(element) => {},其中 element 是一个数组。 - Akhil Ramani

23

在查看这里的所有答案后,由于我的JSON对象是干净的,因此不需要hasOwnProperty进行处理;添加任何额外的javascript处理是没有意义的。这就是我正在使用的全部内容:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}

18
JSON 对象是否干净并不重要。如果在其他时间代码设置了 Object.prototype 上的属性,则会被 for..in 枚举。如果您确定没有使用任何会这样做的库,那么您不需要调用 hasOwnProperty - G-Wiz
4
如果使用Object.create(null)创建,它可以完全干净无污染。 - Ruan Mendes

21

通过使用 原型forEach() 方法,应该跳过原型链上的属性:

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3

2
在使用原型时要小心:obj = { print: 1, each: 2, word: 3 } 会产生 TypeError: number is not a function 的错误。使用 forEach 来匹配类似的 Array 函数可能会减少一些风险。 - David Harkness

19

有趣的是,这些回答中的人们涉及了Object.keys()for...of,但从未将它们结合起来使用:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

因为对象不是迭代器,所以你不能仅使用 for...of 来循环遍历一个 Object , 使用 for...index 或者 .forEach() 循环遍历 Object.keys() 不够优雅和高效。


你可以使普通的对象关联可迭代!直接使用高级特性 for...of ,表现像 Map 一样
DEMO 可在Chrome和FF中运行(我假设此处使用了ES6)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

只要您包含下面我的 shim:

只要您包含下面我的 shim:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

不需要创建一个真正的 Map 对象,它没有良好的语法糖。

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

事实上,使用这个shim后,如果你仍然想利用Map的其他功能(而不是将它们全部shim进去),同时还想使用漂亮的对象表示法,由于对象现在是可迭代的,所以你现在可以直接从中创建一个Map!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});
如果您不喜欢使用shim,或者通常不想处理原型,可以考虑在window上创建该函数,并将其命名为getObjIterator()
//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

现在,您可以将其视为普通函数进行调用,不会影响任何其他内容。

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))


for (let pair of getObjIterator(ordinaryObject))

没有理由不能工作。

欢迎来到未来。


2
Case in point。只要人们往下滚动并发现它有用,那就是最重要的。通常是我试图做某事,不喜欢我在网上看到的东西,最终弄清楚了,然后我回来分享。这是好文档,我曾经在搜索完全忘记的东西之前遇到过自己的答案! - Hashbrown
@JanusTroelsen 你有没有看完整个答案?对于那些不喜欢使用shim或者总体上不想干扰原型的人,可以自由地在window上创建函数,将其命名为getObjIterator(),然后调用它。 - Hashbrown
请注意,这种技术不适用于普通对象,但仍然很有用。 - noɥʇʎԀʎzɐɹƆ
它适用于普通对象,这正是整个重点(以及变量名称如ordinaryObject以强调魔法仍然适用于这些类型)。你有检查过演示吗?@noɥʇʎԀʎzɐɹƆ,哪里出了问题呢?(附言:你的SE个人资料图片很棒) - Hashbrown
我的错,我没有读到关于 shim 的部分。它不能用于未修改原型的普通对象。 - noɥʇʎԀʎzɐɹƆ
显示剩余2条评论

19

Object.keys() 上使用 for-of

例如:

let object = {
  "key1": "value1",
  "key2": "value2",
  "key3": "value3"
};

for (let key of Object.keys(object)) {
  console.log(key + " : " + object[key])
}


18
您也可以使用 Object.keys() 并像下面这样迭代对象键来获取值:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).forEach((key)=> {
 console.log(key +' -> '+ p[key]);
});


你节省了我的时间,谢谢。 - Swap-IOS-Android
很高兴知道 :) - Onera

17

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>


14

Object.keys(obj):数组

检索所有可枚举的自有(非继承)属性中,值为字符串类型的键名。

所以它会提供与通过使用 hasOwnProperty 测试每个对象键相同的键列表。你不需要进行额外的测试操作,只需使用Object.keys( obj ).forEach(function( key ){})即可,而且它被认为更快。让我们来证明一下:

var uniqid = function(){
   var text = "",
     i = 0,
     possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
   for( ; i < 32; i++ ) {
     text += possible.charAt( Math.floor( Math.random() * possible.length ) );
   }
   return text;
  }, 
  CYCLES = 100000,
  obj = {}, 
  p1,
  p2,
  p3,
  key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
 obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
 var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
 if ( obj.hasOwnProperty( key ) ) {
  var waste = obj[ key ];
 }
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

在我的Firefox中,我得到了以下结果:

  • 使用 Object.keys 方法的运行时间为40.21101451665163毫秒。
  • 使用 for...in/hasOwnProperty 方法的运行时间为98.26163508463651毫秒。

PS. 在Chrome上,差异甚至更大http://codepen.io/dsheiko/pen/JdrqXa

PS2: 在ES6(EcmaScript 2015)中,您可以更好地迭代可迭代对象:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});


如果您不想放弃 {} 符号,仍然可以使用 of 而不创建 Map - Hashbrown

14
在最新的ES脚本中,你可以这样做:

let p = {foo: "bar"};
for (let [key, value] of Object.entries(p)) {
  console.log(key, value);
}


可以独立工作,但如果此函数为每个条件返回一个值,则无法工作。 - Harsh Phoujdar

13

将您的对象传递给 Object.keys()。这将返回一个数组,其中包含对象中的所有键。然后,您可以使用 map 循环遍历该数组。在 map 迭代中,使用 obj[key] 其中 obj 是您的对象,key 是当前值,即可获取该键/属性的值。

const obj = { name: "Jane", age: 50 };

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接