如何循环或枚举 JavaScript 对象?

How do I loop through or enumerate a JavaScript object?

提问人:Tanmoy 提问时间:3/26/2009 最后编辑:Mateen UlhaqTanmoy 更新时间:12/9/2022 访问量:2773947

问:

我有一个如下所示的JavaScript对象:

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

如何遍历所有元素(、、...)并获取它们的键和值?pp1p2p3

JavaScript 循环 for 循环

评论


答:

38赞 Richard Levasseur 3/26/2009 #1
for(key in p) {
  alert( p[key] );
}

注意:你可以对数组执行此操作,但你也会遍历 和其他属性。length

评论

4赞 Bryan 3/26/2009
当使用这样的for循环时,只会采用索引值,因此只会发出警报0,1,2等...您需要访问 p[key]。key
1赞 Pencroff 12/5/2013
它是 JavaScript 中最慢的数组迭代方法。您可以在计算机上检查此内容 - 在 JavaScript 中迭代数组的最佳方式
7赞 Sk8erPeter 1/1/2014
@Pencroff:问题在于问题不在于循环遍历数组...... ;)
0赞 Sebastian 8/5/2014
这是我在stackoverflow上不明白的东西。理查德给出了正确的答案,他是第一个给出这个答案的人,但他没有得到任何+1?@Bryan警报中弹出“p1”和“p2”,那有什么问题???var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); }
5赞 Richard Levasseur 8/7/2014
我认为主要区别在于质量:其他答案不仅讲述了如何,还讲述了警告(例如,原型)以及如何处理这些警告。恕我直言,其他答案比我的:)要好。
63赞 Bryan 3/26/2009 #2

你可以像这样迭代它:

for (var key in p) {
  alert(p[key]);
}

请注意,它不会采用属性的值,它只是一个索引值。key

评论

15赞 Vatsal 6/3/2016
这是重复的,甚至不完全正确。您需要检查 hasOwnProperty 才能使其正常工作
4赞 But those new buttons though.. 10/9/2018
我最初根据上述评论对此投了反对票,直到我意识到这个答案是第一位的,因此没有“重复”。它可能不完整,但在许多情况下效果很好。
5153赞 levik 3/26/2009 #3

您可以使用 for-in 循环,如其他人所示。但是,您还必须确保获得的密钥是对象的实际属性,而不是来自原型。

以下是代码片段:

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

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

使用 Object.keys() 替代的 for-of:

var p = {
    0: "value1",
    "b": "value2",
    key: "value3"
};

for (var key of Object.keys(p)) {
    console.log(key + " -> " + p[key])
}

请注意,使用 for-of 而不是 for-in,如果不使用,它将在命名属性上返回 undefined,并且 Object.keys() 确保仅使用对象自己的属性,而不使用整个原型链属性

使用新的 Object.entries() 方法:

注意:Internet Explorer 本身不支持此方法。您可以考虑对较旧的浏览器使用 Polyfill。

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

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

评论

379赞 danieltalsky 1/27/2012
在 javascript 中,每个对象都有一堆内置的键值对,这些键值对具有元信息。当您遍历对象的所有键值对时,您也会遍历它们。hasOwnPropery() 过滤掉这些。
68赞 Ben Y 2/28/2014
实际上,对于...in 未弃用。对于每个...在是。但我真的很喜欢考古学家这个词......我将不得不开始使用它。
0赞 ERROR 401 10/25/2021
如何添加循环的值?谢谢
0赞 mercury 11/5/2021
(对于..in) 表示对象,(for.. of) 表示数组
2赞 jason. 11/1/2022
对于任何关心性能的人来说,+ 在正常使用中 (jsben.ch/pCDAk) 略快,在几千个属性 (jsben.ch/ptzsL) 之外要快得多。for..inhasOwnPropertyObject.keys
377赞 Andreas Grech 3/26/2009 #4

您必须使用 for-in 循环

但是在使用这种循环时要非常小心,因为这将沿原型链循环所有属性

因此,在使用 for-in 循环时,请始终使用该方法来确定迭代中的当前属性是否确实是要检查的对象的属性:hasOwnProperty

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}

评论

31赞 SystemicPlural 4/6/2011
这比 levik 的解决方案更好,因为它允许主逻辑只有一个嵌套循环,而不是两个;使代码更易于阅读。虽然我会松开继续周围的括号;它们是多余的。
55赞 pimvdb 8/5/2011
我不会删除个人,因为没有它们会使人不清楚什么是一部分,什么不是。但我想这只是一个意见问题:){ }ifif
36赞 Andreas Grech 8/5/2011
是的,我更喜欢保留主要以避免混淆,如果以后需要向范围添加一些东西。{ }if
8赞 Andreas Grech 11/11/2011
阅读我之前的评论,我意识到我没有使用正确的术语,因为我说的是“if scope”;但请记住,JavaScript 只有函数作用域。所以我实际上的意思是“如果阻止”。
1368赞 Axel Rauschmayer 4/21/2011 #5

在 ECMAScript 5 下,你可以将 Object.keys() 和 Array.prototype.forEach() 组合在一起:

var obj = { first: "John", last: "Doe" };

Object.keys(obj).forEach(function(key) {
    console.log(key, obj[key]);
});

ECMAScript 6 增加了...的

for (const key of Object.keys(obj)) {
    console.log(key, obj[key]);
}

ECMAScript 8 添加了 Object.entries(),它避免了在原始对象中查找每个值:

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

您可以将 、 解构和 :for...ofObject.entries

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

和 都以与循环相同的顺序迭代属性,但忽略原型链。仅迭代对象自身的可枚举属性。Object.keys()Object.entries()for...in

评论

29赞 David Harkness 6/24/2014
为什么标准没有规定?:(当然会更短,更是补充,但这会让对象定义自己的属性。我想可以防止回调修改对象的键。Object.forEach(obj, function (value, key) {...})obj.forEach(function...)Array.prototype.forEachforEachObject.keys
3赞 run_the_race 8/23/2022
Python 是如此简单,javascript 我每次都必须查找基础知识。
23赞 Francis Lewis 8/19/2011 #6

在浏览了这里的所有答案之后,我自己的使用不需要hasOwnProperty,因为我的json对象是干净的;添加任何额外的 JavaScript 处理真的没有意义。这就是我正在使用的全部内容:

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

评论

18赞 G-Wiz 1/14/2012
JSON 对象是否干净无关紧要。如果在任何其他时间某个代码将属性设置为 ,则它将由 枚举。如果您确定没有使用任何执行此操作的库,则无需调用 .Object.prototypefor..inhasOwnProperty
4赞 Ruan Mendes 4/14/2016
如果用Object.create(null)
17赞 ParaMeterz 2/21/2012 #7

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>

21赞 strider 12/9/2012 #8

通过带有 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赞 David Harkness 6/24/2014
小心原型:生产.使用匹配相似的功能可能会在一定程度上降低风险。obj = { print: 1, each: 2, word: 3 }TypeError: number is not a functionforEachArray
267赞 VisioN 1/21/2013 #9

如果我们不提及循环遍历对象的替代方法,那么这个问题就不完整。

如今,许多著名的 JavaScript 库都提供了自己的方法来迭代集合,即遍历数组、对象和类似数组对象。这些方法使用方便,并且与任何浏览器完全兼容。

  1. 如果您使用 jQuery,则可以使用 jQuery.each() 方法。它可用于无缝迭代对象和数组:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
    
  2. Underscore.js 中,您可以找到方法 _.each(),它遍历元素列表,依次将每个元素生成为提供的函数(注意迭代函数中参数的顺序!

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
    
  3. Lo-Dash 提供了几种迭代对象属性的方法。基本的 _.forEach() (或其别名 )对于遍历对象和数组都很有用,但是 (!) 具有属性的对象被视为数组,为了避免这种行为,建议使用 _.forIn() 和 _.forOwn() 方法(这些方法也有参数在前):_.each()lengthvalue

    _.forIn(obj, function(value, key) {
        console.log(key, value);
    });
    

    _.forIn()遍历对象的自有和继承的可枚举属性,而仅遍历对象的自有属性(基本上是针对函数进行检查)。对于简单对象和对象文本,这些方法中的任何一个都可以正常工作。_.forOwn()hasOwnProperty

通常,所有描述的方法对任何提供的对象都具有相同的行为。此外,使用原生循环通常比任何抽象都快,例如,这些方法相当容易使用,需要更少的编码并提供更好的错误处理。for..injQuery.each()

评论

4赞 Ravi Ram 6/8/2013
要获取值: $.each(obj, function (key, value) { console.log(value.title);
2赞 ppasler 9/8/2017
有趣的是,下划线和jquery如何更改参数:)
58赞 Pencroff 11/17/2013 #10

在 ECMAScript 5 中,您在文字的迭代字段中有了新的方法——Object.keys

更多信息可以在 MDN 上看到

我的选择如下,作为当前版本的浏览器(Chrome30、IE10、FF25)中更快的解决方案

var keys = Object.keys(p),
    len = keys.length,
    i = 0,
    prop,
    value;
while (i < len) {
    prop = keys[i];
    value = p[prop];
    i += 1;
}

您可以在 jsperf.com 上将此方法的性能与不同的实现进行比较:

您可以在 Kangax 的兼容性表上看到浏览器支持

对于旧浏览器,您有简单完整的 polyfill

更新:

这个问题中所有最常见案例的性能比较:perfjs.info

对象文本迭代

12赞 mohamed-ibrahim 4/21/2015 #11

只有没有依赖项的 JavaScript 代码:

var p = {"p1": "value1", "p2": "value2", "p3": "value3"};
keys = Object.keys(p);   // ["p1", "p2", "p3"]

for(i = 0; i < keys.length; i++){
  console.log(keys[i] + "=" + p[keys[i]]);   // p1=value1, p2=value2, p3=value3
}
14赞 Dmitry Sheiko 6/22/2015 #12

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 毫秒。
  • 为。。。in/hasOwnProperty 方法耗时 98.26163508463651 毫秒。

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

评论

0赞 Hashbrown 6/28/2016
如果你不想放弃 {} 表示法,你仍然可以在不创建 Maps 的情况下使用of
6赞 Lewis 7/9/2015 #13

我会这样做,而不是在每个循环中检查。obj.hasOwnerPropertyfor ... in

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}
8赞 Nicolas Bouvrette 6/18/2016 #14

使用纯 JavaScript 时,循环可能非常有趣。似乎只有 ECMA6(2015 年新 JavaScript 规范)控制了循环。不幸的是,在我写这篇文章的时候,浏览器和流行的集成开发环境(IDE)仍在努力完全支持新的花里胡哨的东西。

一目了然,这是 ECMA6 之前的 JavaScript 对象循环的样子:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

另外,我知道这超出了这个问题的范围,但在 2011 年,ECMAScript 5.1 添加了仅数组的方法,这基本上创造了一种新的改进方法来循环遍历数组,同时仍然保留不可迭代的对象与旧的冗长和令人困惑的循环。但奇怪的是,这种新方法不支持,这导致了各种其他问题。forEachforforEachbreak

基本上在 2011 年,除了许多流行的库(jQuery、Underscore 等)决定重新实现之外,没有一种真正可靠的方法来循环 JavaScript。

截至 2015 年,我们现在有一种更好的开箱即用方法来循环(和中断)任何对象类型(包括数组和字符串)。以下是当推荐成为主流时 JavaScript 中的循环最终会是什么样子:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

请注意,自 2016 年 6 月 18 日起,大多数浏览器将不支持上述代码。即使在 Chrome 中,您也需要启用此特殊标志才能使其工作:chrome://flags/#enable-javascript-harmony

在这成为新标准之前,仍然可以使用旧方法,但在流行的库中也有替代方案,甚至是那些不使用任何这些库的人的轻量级替代方案

评论

0赞 abalter 6/18/2016
你能提供这个工作的小提琴吗?这是我的尝试。jsfiddle.net/abalter/sceeb211
0赞 Nicolas Bouvrette 6/18/2016
@abalter 对不起,我意识到我的代码中有错别字。我修复了它并在这里更新了您的 JsFiddle:jsfiddle.net/sceeb211/2
0赞 abalter 6/19/2016
我在 chrome 中并得到 .它还没有在 chrome 中实现吗?Uncaught TypeError: Object.entries is not a function
0赞 Nicolas Bouvrette 6/19/2016
@abalter是的。确保您使用的是 Chrome 版本 51,并且您已经启用了该标志,如我的编辑和 Jsfiddle 评论中所述。您可以在此处查看详细信息:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
0赞 abalter 6/19/2016
对不起,我错过了关于旗帜的信息。我看到它还不是一个完全实现的功能。
19赞 Hashbrown 6/28/2016 #15

有趣的是,这些答案中的人们都触及了两者,但从未将它们结合起来:Object.keys()for...of

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

你不能只是为了... 的对象,因为它不是迭代器,并且...index 或 .forEach() 将 Object.keys() 与 Object.keys() 联系起来是丑陋的/低效的。
我很高兴大多数人都避免......(无论是否检查 .hasOwnProperty()),因为这也有点混乱,所以除了我上面的答案之外,我在这里要说......


你可以让普通的对象关联迭代!行为就像地图一样,直接使用花哨的...
Chrome 和 FF 中工作的 DEMO(我假设仅限 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);

只要你在下面包括我的垫片:

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

事实上,有了这个填充码,如果你仍然想利用 Map 的其他功能(而不是将它们全部填充),但仍然想使用简洁的对象符号,因为对象现在是可迭代的,你现在可以用它制作一个 Map!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

对于那些不喜欢填充或弄乱原型的人,可以随意在窗口上创建函数,然后将其称为 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赞 Hashbrown 7/22/2016
举个例子。只要人们向下滚动并发现它有帮助,这才是最重要的。通常是我试图做一些事情,不喜欢我在网上看到的东西,最终弄清楚了,然后我回来分享。这很好,doco,在谷歌搜索我完全忘记的事情之前,我实际上已经遇到了自己的答案!
0赞 Janus Troelsen 9/30/2016
@HelpMeStackOverflowMyOnlyHope 就我个人而言,我不喜欢修改我自己没有定义的对象的原型。
0赞 Hashbrown 9/30/2016
@JanusTroelsen你读过整个答案吗?For those who don't like to shim, or mess with prototype in general, feel free to make the function on window instead, calling it something like getObjIterator() then;
0赞 noɥʇʎԀʎzɐɹƆ 6/14/2018
请注意,此技术不适用于普通对象,但仍然有用。
0赞 Hashbrown 6/15/2018
它确实适用于普通对象,这实际上是重点(以及变量名称,例如强调魔术仍然适用于这些类型)。你检查过演示了吗?什么对你不起作用,@no ɥʇʎҁʎzɐɹƆ?(P.S. 你的SE个人资料图片是老板)ordinaryObject
37赞 FieryCod 8/27/2016 #16

由于 es2015 越来越受欢迎,我发布了这个答案,其中包括使用生成器和迭代器来平滑地迭代成对。正如在其他语言中一样,例如 Ruby。[key, value]

好的,这里有一个代码:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function*() {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

有关如何执行迭代器和生成器的所有信息,都可以在开发人员Mozilla页面上找到。

希望它帮助了某人。

编辑:

ES2017 将包括这将使对象中的对迭代更加容易。现在已知,根据 ts39 阶段信息,它将成为标准的一部分。Object.entries[key, value]

我认为是时候更新我的答案了,让它变得比现在更新鲜。

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

你可以在 MDN 页面上找到更多关于用法的信息

评论

0赞 Dean Radcliffe 9/29/2017
这对我来说看起来完全是多余的/不需要的。你会把它添加到系统中的每个对象吗?我认为提供迭代器的目的是这样您就可以执行'for( const [k, v] of myObject )'。它看起来只是提供很少额外价值的额外代码。
6赞 Bamieh 9/20/2016 #17

在 ES6 中,我们有众所周知的符号来公开一些以前的内部方法,你可以用它来定义迭代器如何为这个对象工作:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

这将给出与使用 for 相同的结果...在 ES6 循环中。

for(var key in p) {
    console.log(key);
}

但重要的是要知道你现在使用 es6 所拥有的功能!

评论

1赞 ooo 5/3/2019
自定义对象迭代器调用由内存生成并在内存中分配的数组的内置数组迭代器...凉!Object.keys()
8赞 Biber 11/23/2016 #18

您可以向所有对象添加一个简单的 forEach 函数,以便您可以自动遍历任何对象:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        for (var key in this) {
            if (!this.hasOwnProperty(key)) {
                // skip loop if the property is from prototype
                continue;
            }
            var value = this[key];
            func(key, value);
        }
    },
    enumerable: false
});

对于那些不喜欢“为了......in“方法:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        var arr = Object.keys(this);
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i];
            func(key, this[key]);
        }
    },
    enumerable: false
});

现在,您可以简单地调用:

p.forEach (function(key, value){
    console.log ("Key: " + key);
    console.log ("Value: " + value);
});

如果您不想与其他 forEach-Methods 发生冲突,则可以使用您的唯一名称来命名它。

评论

3赞 Moritz 1/6/2017
修改内置对象(如)的原型通常被认为是一种反模式,因为它很容易导致与其他代码的冲突。所以伤口建议这样做。Object
11赞 Muhammad Usman 11/17/2017 #19

该方法返回给定对象自己的可枚举属性的数组。在这里阅读更多关于它的信息Object.keys()

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

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))

11赞 Harsh Patel 12/20/2017 #20

这是遍历对象的另一种方法。

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


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

评论

3赞 Rolf 3/10/2018
这很酷,但是对于大型对象,该方法的性能可能更高。for
72赞 T.J. Crowder 7/10/2018 #21

前言:

  • 对象属性可以是自己的(属性位于对象本身上),也可以是继承的(不是在对象本身上,而是在其原型之一上)。
  • 对象属性可以是枚举的,也可以是不可枚举的。不可枚举的属性被排除在许多属性枚举/数组之外。
  • 属性名称可以是字符串或符号。名称为 Symbols 的属性被排除在许多属性枚举/数组之外。

在 2018 年,循环遍历对象属性的选项如下(列表后面有一些示例):

  1. for-in [MDNspec] — 一个循环结构,循环遍历对象的可枚举属性的名称,包括继承的属性,其名称为字符串
  2. Object.keys [MDNspec] — 一个函数,提供对象自己的可枚举属性的名称数组,这些属性的名称是字符串。
  3. Object.values [MDNspec] — 一个函数,提供对象自己的可枚举属性的值数组。
  4. Object.entries [MDNspec] — 一个函数,提供对象自己的可枚举属性的名称值的数组(数组中的每个条目都是一个数组)。[name, value]
  5. Object.getOwnPropertyNames [MDNspec] — 一个函数,提供对象自身属性(甚至是不可枚举的属性)名称的数组,其名称为字符串。
  6. Object.getOwnPropertySymbols [MDNspec] — 一个函数,提供对象自身属性(甚至是不可枚举的属性)名称的数组,其名称为 Symbols。
  7. Reflect.ownKeys [MDNspec] — 一个函数,提供对象自身属性(甚至是不可枚举的属性)的名称数组,无论这些名称是字符串还是符号。
  8. 如果你想要一个对象的所有属性,包括不可枚举的继承属性,你需要使用循环和 [MDNspec] 并使用 、 或 原型链中的每个对象(本答案底部的示例)。Object.getPrototypeOfObject.getOwnPropertyNamesObject.getOwnPropertySymbolsReflect.ownKeys

对于除 之外的所有方法,您将在数组(、、等)上使用某种循环结构。for-inforfor-offorEach

例子:

进场

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name in o) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.keys(带有 for-of 循环,但您可以使用任何循环结构):

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.keys(o)) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.values

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const value of Object.values(o)) {
    console.log(`${value}`);
}

Object.entries

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const [name, value] of Object.entries(o)) {
    console.log(`${name} = ${value}`);
}

Object.getOwnPropertyNames

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertyNames(o)) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.getOwnPropertySymbols

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertySymbols(o)) {
    const value = o[name];
    console.log(`${String(name)} = ${value}`);
}

Reflect.ownKeys

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Reflect.ownKeys(o)) {
    const value = o[name];
    console.log(`${String(name)} = ${value}`);
}

所有属性,包括继承的不可枚举属性:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (let depth = 0, current = o; current; ++depth, current = Object.getPrototypeOf(current)) {
    for (const name of Reflect.ownKeys(current)) {
        const value = o[name];
        console.log(`[${depth}] ${String(name)} = ${String(value)}`);
    }
}
.as-console-wrapper {
  max-height: 100% !important;
}

评论

1赞 serraosays 4/22/2019
很好地添加了可枚举/不可编号的对象属性。
14赞 Ankit 9/11/2018 #22

在最新的 ES 脚本中,您可以执行如下操作:

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

评论

0赞 Harsh Phoujdar 9/16/2020
作为独立函数工作,但如果此函数为每个 for 条件返回一个值,则不起作用
18赞 Onera 8/13/2019 #23

您还可以使用 Object.keys() 并遍历对象键,如下所示以获取值:

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

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

评论

0赞 Swap-IOS-Android 9/18/2019
你节省了我的时间,谢谢
0赞 Onera 9/26/2019
很高兴知道:)
19赞 Nicolas Cabanas 10/31/2019 #24

Object.keys() 上使用 for-of

喜欢:

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

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

10赞 akhtarvahid 1/4/2020 #25

在 javascript 中迭代对象的多种方式

用于...在循环中

 var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};
for (let key in p){
   if(p.hasOwnProperty(key)){
     console.log(`${key} : ${p[key]}`)
   }
}

用于...OF 循环

 var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};
for (let key of Object.keys(p)){
     console.log(`key: ${key} & value: ${p[key]}`)
}

forEach() 与 Object.keys、Object.values、Object.entries 一起使用

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};
Object.keys(p).forEach(key=>{
   console.log(`${key} : ${p[key]}`);
});
Object.values(p).forEach(value=>{
   console.log(value);
});
Object.entries(p).forEach(([key,value])=>{
    console.log(`${key}:${value}`)
})

7赞 AmerllicA 2/23/2020 #26

循环使用可枚举的 JavaScript 对象的一个好方法是使用 or with using 函数,这对 ReactJS 来说可能很棒且很常见。如下图所示:Object.keysObject.entriesmap

// assume items:

const items = {
  first: { name: 'phone', price: 400 },
  second: { name: 'tv', price: 300 },
  third: { name: 'sofa', price: 250 },
};

用于循环并显示一些 UI,如下所示:ReactJS

~~~
<div>
  {Object.entries(items).map(([key, ({ name, price })]) => (
    <div key={key}>
     <span>name: {name}</span>
     <span>price: {price}</span>
    </div>
  ))}
</div>

实际上,我使用了两次解构赋值,一次用于获取,一次用于获取和.keynameprice

评论

0赞 Mob_Abominator 8/19/2020
当我使用 React 以及 for 循环如何在内部不起作用时,我正在寻找这个,这是完美的解决方案。多谢<Fragment>
0赞 AmerllicA 8/19/2020
亲爱的@Mob_Abominator,感谢您的甜蜜评论,我很高兴听到它对您有用。但我不明白.还有问题吗?如果是这样,请留下问题并告诉我,我会回答。如果什么都没有留下,你现在没事了。请给我的这篇文章投赞成票。谢谢。how for loops don't work inside <Fragment>
48赞 Kamil Kiełczewski 3/7/2020 #27

性能

今天 2020.03.06 我在 MacOs High Sierra v80.0.5 上的 Chrome v13.0.5、Safari v13.0.5 和 Firefox 10.13.6 上对选定的解决方案进行了测试

结论

  • 基于(A,B)的解决方案对于所有浏览器的大型和小型对象都是快速(或最快)的for-in
  • 令人惊讶的是,(H)解决方案在铬上对小型和大型物体都很快for-of
  • 基于显式索引 (J,K) 的解决方案在所有浏览器上对于小对象都非常快(对于 firefox,对于大 ojbects 也很快,但在其他浏览器上速度中等)i
  • 基于迭代器(D,E)的解决方案最慢,不推荐使用
  • 解决方案 C 对于大物体是慢速的,对于小物体是中慢的

在此处输入图像描述

进行了性能测试

  • 小物体 - 有 3 个字段 - 您可以在您的机器上执行测试 这里
  • “大”对象 - 有 1000 个字段 - 您可以在您的机器上执行测试 这里

以下代码片段介绍了使用的解决方案

function A(obj,s='') {
	for (let key in obj) if (obj.hasOwnProperty(key)) s+=key+'->'+obj[key] + ' ';
  return s;
}

function B(obj,s='') {
	for (let key in obj) s+=key+'->'+obj[key] + ' ';
  return s;
}

function C(obj,s='') {
  const map = new Map(Object.entries(obj));
	for (let [key,value] of map) s+=key+'->'+value + ' ';
  return s;
}

function D(obj,s='') {
  let o = { 
    ...obj,
    *[Symbol.iterator]() {
      for (const i of Object.keys(this)) yield [i, this[i]];    
    }
  }
  for (let [key,value] of o) s+=key+'->'+value + ' ';
  return s;
}

function E(obj,s='') {
  let o = { 
    ...obj,
    *[Symbol.iterator]() {yield *Object.keys(this)}
  }
  for (let key of o) s+=key+'->'+o[key] + ' ';
  return s;
}

function F(obj,s='') {
	for (let key of Object.keys(obj)) s+=key+'->'+obj[key]+' ';
  return s;
}

function G(obj,s='') {
	for (let [key, value] of Object.entries(obj)) s+=key+'->'+value+' ';
  return s;
}

function H(obj,s='') {
	for (let key of Object.getOwnPropertyNames(obj)) s+=key+'->'+obj[key]+' ';
  return s;
}

function I(obj,s='') {
	for (const key of Reflect.ownKeys(obj)) s+=key+'->'+obj[key]+' ';
  return s;
}

function J(obj,s='') {
  let keys = Object.keys(obj);
	for(let i = 0; i < keys.length; i++){
    let key = keys[i];
    s+=key+'->'+obj[key]+' ';
  }
  return s;
}

function K(obj,s='') {
  var keys = Object.keys(obj), len = keys.length, i = 0;
  while (i < len) {
    let key = keys[i];
    s+=key+'->'+obj[key]+' ';
    i += 1;
  }
  return s;
}

function L(obj,s='') {
  Object.keys(obj).forEach(key=> s+=key+'->'+obj[key]+' ' );
  return s;
}

function M(obj,s='') {
  Object.entries(obj).forEach(([key, value]) => s+=key+'->'+value+' ');
  return s;
}

function N(obj,s='') {
  Object.getOwnPropertyNames(obj).forEach(key => s+=key+'->'+obj[key]+' ');
  return s;
}

function O(obj,s='') {
  Reflect.ownKeys(obj).forEach(key=> s+=key+'->'+obj[key]+' ' );
  return s;
}



// TEST

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};
let log = (name,f) => console.log(`${name} ${f(p)}`)

log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This snippet only presents choosen solutions

这是铬上小物体的结果

在此处输入图像描述

评论

0赞 vir us 12/8/2023
我想这取决于上下文,但那是书的东西。没有不尊重或否认为这个答案付出的努力,但对于一般的消费者应用程序,我总是发现那些迂腐的性能测试脱离了现实生活的背景。好的,可以在这里和那里节省 5 毫秒。没有一个用户会注意到这一点。在 80 年代至 90 年代,当 CPU 周期昂贵时,这可能会有所作为,但今天这在 99.9% 的时间里几乎无关紧要。开发人员的时间比这些微观优化的结果要昂贵得多,尤其是当用户体验改进可以忽略不计或根本不存在时。
26赞 Akhil Ramani 8/28/2021 #28

单行和更易读的代码可以..

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

评论

0赞 Nivethan 5/3/2022
很好的答案,它比上述解决方案更具可读性,但您能解释一下答案中的 .map(([key, value]) 会发生什么吗?
1赞 Akhil Ramani 5/6/2022
@Nivethan Object.entries 的输出将是数组的数组。即 [ ['key1', 'value'], ['key2', 'value'] ] 因此,map 将遍历外部数组,每个数组元素一个接一个地传递到其回调函数中。因此,在这里我使用了数组解构语法 ([key, value]) => {} 而不是 (element) => {},其中 element 是一个数组。
8赞 lodey 2/3/2022 #29
Object.entries(myObject).map(([key, value]) => console.log(key, value))

你可以试试这样。 将某某,这将产生键和值。所以这里的键是 ,值是 ,而 值就像 、 一样。myObject{name: "", phone: ""}namephonedog123123

{name: "dog"}

这里键是,值是。namedog

评论

0赞 Maximilian Peters 2/9/2022
您好,欢迎来到 Stackoverflow!正如导览中所解释的,这个网站是一个有用的问题及其答案的存储库。您的答案与其他答案没有本质区别,也不是很有用,因为它不会添加任何新的价值或信息。请避免写重复的答案,编辑您的答案以增加价值或完全删除它,这将确保网站上的所有问题和答案都保持有用,而不是分散/重复。
13赞 Isaac Jandalala 6/14/2022 #30

将对象传递给 。这将返回一个包含对象中所有键的数组。然后,您可以使用 遍历数组。使用 where 是您的对象,并且是映射迭代中的当前值,您可以获取该键/属性的值。Object.keys()mapobj[key]objkey

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

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