题 如何循环或枚举JavaScript对象?


我有一个像以下JavaScript对象:

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

现在我想循环遍历所有 p 元素(p1p2p3......)并获得他们的钥匙和价值观。我怎样才能做到这一点?

如有必要,我可以修改JavaScript对象。我的最终目标是遍历一些键值对,如果可能的话,我想避免使用 eval


2133
2018-03-26 06:01


起源


我将JSON更改为JavaScript(对象)以避免混淆对象文字和JSON。 - Felix Kling
在迭代集合时,您应该关注优化。因为它可能影响页面性能。 - Zaheer Ahmed
漂亮的打印Javascript:  j11y.io/demos/prettyprint  我是一个狂热的粉丝 转储功能  ajaxian.com/archives/javascript-variable-dump-in-coldfusion - Kiquenet
转储功能:  github.com/ozmartian/js-cfdump - Kiquenet


答案:


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

这是片段:

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

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


3467
2018-03-26 06:12



建议你改变警戒线只是为了清楚 alert(key + " -> " + JSON.stringify(p[key])); - Steve Midgley
你能解释一下hasOwnProperty的必要性吗?你的原型是什么意思? - kamaci
在javascript中,每个对象都有一堆具有元信息的内置键值对。循环遍历对象的所有键值对时,也会循环遍历它们。 hasOwnPropery()过滤掉这些。 - danieltalsky
其实, 对于在... 不推荐使用。 对于每个... in 是。但我真的很喜欢这个词 考古学家......我将不得不开始使用它。 - Ben Y
javascript中的每个对象(实际上是一个键值对)都有一个名为的属性 __proto__ 要么 prototype。此属性具有对其父对象的引用。对象自动从其父级继承属性。这就是使用的原因 hasOwnProperty,这表示我们对对象拥有属性感兴趣,而不是对其父对象感兴趣。 - Zubair Alam


在ECMAScript 5下,您可以组合使用 Object.keys() 和 Array.prototype.forEach()

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

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

ES6补充道 for...of

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

ES2017补充道 Object.entries() 这避免了必须查找原始对象中的每个值:

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

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

编辑:ES2016→ES6


627
2018-04-20 21:59



标准为何没有提供 Object.forEach(obj, function (value, key) {...})? :(当然 obj.forEach(function...) 将更短和补充 Array.prototype.forEach,但这会让对象定义自己的风险 forEach 属性。我想 Object.keys 防止修改对象密钥的回调。 - David Harkness
Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); } - David Harkness
@DavidHarkness ES2017中有Object.entries。在那里你可以做到以下几点: Object.entries(obj).map/forEach(([key, value]) => console.log(key, value)) ([key,value]是数组解构,直接访问这两个项目。你必须将参数包装在额外的parens中。) - Andreas Linnert
如何得到 index 在json的关键?或者如果需要,我应该使用单独的柜台? - Saravanabalagi Ramachandran
for...of 是ES6标准,而不是ES2016。 - Rax Weber


你必须使用 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
}

300
2018-03-26 06:12



这比levik的解决方案更好,因为它允许主逻辑只有一个嵌套循环,而不是两个;使代码更容易阅读。虽然我松开了继续周围的括号;它们是多余的。 - SystemicPlural
我不会删除 { } 个人因为一个 if 没有他们会让人有点不清楚是什么的一部分 if 什么不是。但我想这只是一个意见问题:) - pimvdb
是的,我更喜欢保持 { } 主要是为了避免混淆,如果后来需要添加一些东西 if 范围。 - Andreas Grech
阅读我之前的评论,我意识到我没有使用正确的术语,因为我说“如果范围”;但请记住,JavaScript只有函数范围。所以我实际上的意思是“if block”。 - Andreas Grech
eomeroff,如果你真的很担心,你可以做以下事情: Object.prototype.hasOwnProperty.call(p, prop)  但是,这也无法防止对Object.prototype的操作...... - jordancpaul


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

如今,许多众所周知的JavaScript库提供了自己的迭代集合的方法,即over 阵列对象,和 类似数组的对象。这些方法使用方便,并且与任何浏览器完全兼容。

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

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
    
  2. Underscore.js 你可以找到方法 _.each(),迭代一个元素列表,依次产生一个提供的函数(注意参数的顺序) iteratee 功能!):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
    
  3. 罗短跑 提供了几种迭代对象属性的方法。基本 _.forEach() (或者它的别名 _.each())用于循环遍历对象和数组,但是(!)对象 length 属性被视为数组,为避免这种行为,建议使用 _.forIn() 和 _.forOwn() 方法(这些也有 value 争论第一):

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

    _.forIn() 迭代 拥有和继承 对象的可枚举属性,而 _.forOwn() 只迭过 拥有 对象的属性(基本上是检查 hasOwnProperty 功能)。对于简单对象和对象文字,这些方法中的任何一种都可以正常工作。

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


231
2018-01-20 17:58



获取值:$ .each(obj,function(key,value){console.log(value.title);}); - Ravi Ram
只是有趣的下划线和jquery如何改变参数:) - ppasler


在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的compat表

对于旧浏览器,你有 简单 和 充分 填充工具

UPD:

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

对象文字迭代


47
2017-11-16 19:59



的确,我只想发布这种方法。但你打败了我:( - Jamie Hutber
jsperf.com/object-iteration-comparison - Jason


您可以像以下一样迭代它:

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

注意 key 不会承担财产的价值,它只是一个指数值。


30
2018-03-26 06:05



这是重复的,甚至不完全正确。您需要检查hasOwnProperty才能使其正常工作 - Vatsal


由于es2015越来越受欢迎,我发布这个答案,包括使用生成器和迭代器来顺利迭代 [key, value] 对。因为在其他语言中可以使用例如Ruby。

好的,这是一个代码:

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将包括 Object.entries 这会迭代 [key, value] 对象中的对更加容易。现在已经知道它将成为标准的一部分 ts39 舞台信息。

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

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 页


24
2017-08-27 09:06



谢谢!现在我的同事们不会嘲笑我的2005款JS! - the0ther
这看起来完全是多余的/不需要我的。您会将它添加到系统中的每个对象吗?我认为提供迭代器的重点是你可以做`for(const [k,v] of myObject)'。它看起来像额外的代码提供了额外的价值。 - Dean Radcliffe