如何循环或枚举JavaScript对象?
我有一个JavaScript对象,如下所示:
var p = { "p1": "value1", "p2": "value2", "p3": "value3" };
现在我想遍历所有p
元素( p1
, p2
, p3
…)并获得它们的键和值。 我怎样才能做到这一点?
如有必要,我可以修改JavaScript对象。 我的最终目标是循环通过一些关键值对,如果可能的话,我想避免使用eval
。
您可以使用其他人所示的for-in
循环。 但是,您还必须确保所获得的密钥是对象的实际属性,而不是来自原型。
这里是片段:
var p = { "p1": "value1", "p2": "value2", "p3": "value3" }; for (var key in p) { if (p.hasOwnProperty(key)) { console.log(key + " -> " + p[key]); } }
在ECMAScript 5下,可以结合Object.keys()
和Array.prototype.forEach()
:
var obj = { first: "John", last: "Doe" }; Object.keys(obj).forEach(function(key) { console.log(key, obj[key]); });
ES2016增加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()
以与for...in
循环相同的顺序迭代属性, 但忽略原型链 。 只有对象自己的枚举属性被迭代。
你必须使用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 }
如果我们没有提到循环对象的替代方法,这个问题就不会完整。
现在,许多知名的JavaScript库提供了自己的迭代集合的方法,即通过数组 , 对象和类似数组的对象 。 这些方法使用方便,并且完全兼容任何浏览器。
-
如果你使用jQuery ,你可以使用
jQuery.each()
方法。 它可以用来无缝遍历对象和数组:$.each(obj, function(key, value) { console.log(key, value); });
-
在
_.each()
,你可以find方法_.each()
,它遍历元素列表,每个依次产生一个提供的函数(注意iteratee函数中参数的顺序!):_.each(obj, function(value, key) { console.log(key, value); });
-
Lo-Dash提供了几种迭代对象属性的方法。 基本的
_.forEach()
(或者它的别名_.each()
)对循环对象和数组非常有用,但是具有length
属性的(!)对象像数组一样对待,为了避免这种行为,build议使用_.forIn()
和_.forOwn()
方法(这些方法也value
参数):_.forIn(obj, function(value, key) { console.log(key, value); });
_.forIn()
遍历一个对象的自己和inheritance的可枚举属性,而_.forOwn()
仅遍历一个对象的自身属性(基本上检查hasOwnProperty
函数)。 对于简单的对象和对象文字,任何这些方法都可以正常工作。
通常,所有描述的方法与任何提供的对象具有相同的行为。 除了使用本地for..in
循环通常比任何抽象如jQuery.each()
更快 ,这些方法相当容易使用,需要更less的编码,并提供更好的error handling。
在ECMAScript 5中,您可以在文字Object.keys
迭代字段中使用新的方法
您可以在MDN上看到更多信息
我的select是作为一个更快的解决scheme在当前版本的浏览器(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表上看到
对于旧的浏览器,你有简单和充分的 polyfill
UPD:
性能比较在perfjs.info
这个问题上的所有最stream行的案例:
对象字面迭代
你可以像遍历它一样:
for (var key in p) { alert(p[key]); }
请注意, key
不会取得属性的值,它只是一个索引值。
通过原型与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
在查看这里的所有答案后,hasOwnProperty不是我自己用法所必需的,因为我的json对象是干净的; 添加任何额外的JavaScript处理真的没有意义。 这是我正在使用的所有:
for (var key in p) { console.log(key + ' => ' + p[key]); // key is key // value is p[key] }
Object.keys(obj):Array
检索所有可枚举自己(非inheritance)属性的所有string值的键。
因此,通过使用hasOwnPropertytesting每个对象键,它可以提供相同的键列表。 你不需要额外的testing操作, Object.keys( obj ).forEach(function( key ){})
应该会更快。 我们来certificate一下:
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.");
由于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页面find更多关于使用情况的信息
在这些答案中有趣的人已经触及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...in
(不pipe是否检查.hasOwnProperty()
),因为这也有点混乱,所以除了我上面的回答,我在这里说…
你可以使普通的对象关联迭代! performance就像Map
s直接使用幻想for...of
在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; }}; };
而不必创build一个真正的Map对象,它没有很好的语法糖。
var trueMap = new Map([['well', 'hello'], ['there', '!']]); for (let pair of trueMap) console.log(pair[0] + ':' + pair[1]);
事实上,如果你仍然想利用Map的其他function(而不是将它们全部填满),但是仍然希望使用整齐的对象符号,因为对象现在可以迭代了,现在可以从中创build一个Map!
//shown in demo var realMap = new Map({well:'hello', there:'!'});
对于那些不喜欢的人来说,或者不喜欢一般的prototype
,可以自由地在窗口上做这个函数,然后像getObjIterator()
那样调用它。
var realMap = new Map(getObjIterator({well:'hello', there:'!'}))
要么
for (let pair of getObjIterator(ordinaryObject))
没有理由不这样做。
欢迎来到未来
var p = { "p1": "value1", "p2": "value2", "p3": "value3" }; for (var key in p) { if (p.hasOwnProperty(key)) { alert(key + " = " + p[key]); } } --------------------------- --------------------------- Output: p1 = values1 p2 = values2 p3 = values3
for(key in p) { alert( p[key] ); }
注意:你可以通过数组来完成这个任务,但是你也可以迭代length
和其他属性。
您可以将一个简单的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 });
对于那些不喜欢“ for … 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发生冲突,则可以用您的唯一名称命名。
我会这样做,而不是检查每一个obj.hasOwnerProperty
for ... 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"); }
如果你想迭代不可枚举的属性 ,你可以使用Object.getOwnPropertyNames(obj)
来返回直接在给定对象上find的所有属性(可枚举或不可枚举)的数组。
var obj = Object.create({}, { // non-enumerable property getFoo: { value: function() { return this.foo; }, enumerable: false } }); obj.foo = 1; // enumerable property Object.getOwnPropertyNames(obj).forEach(function (name) { document.write(name + ': ' + obj[name] + '<br/>'); });
只有没有依赖关系的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 }
使用纯JavaScript时,循环可能会非常有趣。 看来,只有ECMA6(2015年新的JavaScript规范)得到了控制的循环。 不幸的是,在我写这篇文章的时候,浏览器和stream行的集成开发环境(IDE)仍然在努力完全支持新的function。
一眼就可以看出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增加了forEach
方法的数组,只是基本上创build了一个新的改进的方式来循环通过数组,同时仍然留下不可迭代的对象与旧的详细和令人困惑for
循环。 但奇怪的是,这个新的forEach
方法不支持导致各种其他问题的break
。
基本上在2011年,除了许多stream行的库(jQuery,Underscore等)决定重新实现之外,还没有真正可靠的JavaScript循环方法。
截至2015年,我们现在有更好的开箱即用的方式来循环(和中断)任何对象types(包括数组和string)。 下面是当推荐成为主stream时,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
直到这成为新的标准,旧的方法仍然可以使用,但也有stream行的图书馆的替代品,甚至没有使用任何这些图书馆的轻量级替代品 。
考虑到ES6我想添加我自己的勺糖,并提供一个更多的方法来迭代对象的属性。
由于普通的JS对象不能迭代 ,所以我们无法使用for..of
循环遍历其内容。 但是没有人能阻止我们使其迭代 。
让我们有book
对象。
let book = { title: "Amazing book", author: "Me", pages: 3 } book[Symbol.iterator] = function(){ let properties = Object.keys(this); // returns an array with property names let counter = 0; let isDone = false; let next = () => { if(counter >= properties.length){ isDone = true; } return { done: isDone, value: this[properties[counter++]] } } return { next }; }
既然我们已经做到了,我们可以这样使用它:
for(let pValue of book){ console.log(pValue); } ------------------------ Amazing book Me 3
或者如果您知道ES6 生成器的function ,那么您肯定可以使代码更短。
book[Symbol.iterator] = function *(){ let properties = Object.keys(this); for (let p of properties){ yield this[p]; } }
当然,您可以将所有对象的这种行为应用于prototype
级别的Object
迭代。
Object.prototype[Symbol.iterator] = function() {...}
此外,符合可迭代协议的对象可以与新的ES2015特征扩展运算符一起使用,因此我们可以将对象属性值作为数组读取。
let pValues = [...book]; console.log(pValues); ------------------------- ["Amazing book", "Me", 3]
或者你可以使用解构赋值:
let [title, , pages] = book; // notice that we can just skip unnecessary values console.log(title); console.log(pages); ------------------ Amazing book 3
你可以用上面提供的所有代码检查JSFiddle 。
如果有人需要通过arrayObjects循环条件 :
var arrayObjects = [{"building":"A", "status":"good"},{"building":"B","status":"horrible"}]; for (var i=0; i< arrayObjects.length; i++) { console.log(arrayObjects[i]); for(key in arrayObjects[i]) { if (key == "status" && arrayObjects[i][key] == "good") { console.log(key + "->" + arrayObjects[i][key]); }else{ console.log("nothing found"); } } }
在ES6中我们有一些众所周知的符号来公开一些以前的内部方法,你可以用它来定义这个对象的迭代器是如何工作的:
var p = { "p1": "value1", "p2": "value2", "p3": "value3", *[Symbol.iterator]() { yield *Object.keys(this); } }; [...p] //["p1", "p2", "p3"]
这将给出与在es6循环中使用…相同的结果。
for(var key in p) { console.log(key); }
但重要的是知道你现在使用es6的function!
一个对象在实现.next()方法时变成一个迭代器
const james = { name: 'James', height: `5'10"`, weight: 185, [Symbol.iterator]() { let properties = [] for (let key of Object.keys(james)){ properties.push(key); } index = 0; return { next: () => { let key = properties[index]; let value = this[key]; let done = index >= properties.length - 1 ; index++; return { key, value, done }; } }; } }; const iterator = james[Symbol.iterator](); console.log(iterator.next().value); // 'James' console.log(iterator.next().value); // `5'10` console.log(iterator.next().value); // 185
由于ES2015可以使用for循环,直接访问元素:
// before ES2015 for(var key of elements){ console.log(elements[key]); } // ES2015 for(let element of elements){ console.log(element); }
希望这有助于某人。
使用Angular时遇到了类似的问题,下面是我find的解决scheme。
第1步。获取所有的对象键。 使用Object.keys。 这个方法返回一个给定对象自己可枚举属性的数组。
第2步。创build一个空数组。 这是一个所有属性都将生存的地方,因为你的新的ngFor循环将指向这个数组,所以我们必须把它们全部抓住。 第3步。迭代抛出所有的键,并推动每一个你创build的数组。 这是代码中的样子。
// Evil response in a variable. Here are all my vehicles. let evilResponse = { "car" : { "color" : "red", "model" : "2013" }, "motorcycle": { "color" : "red", "model" : "2016" }, "bicycle": { "color" : "red", "model" : "2011" } } // Step 1. Get all the object keys. let evilResponseProps = Object.keys(evilResponse); // Step 2. Create an empty array. let goodResponse = []; // Step 3. Iterate throw all keys. for (prop of evilResponseProps) { goodResponse.push(evilResponseProps[prop]); }
这是原始post的链接。 https://medium.com/@papaponmx/looping-over-object-properties-with-ngfor-in-angular-869cd7b2ddcc
除了提问者(' 最终目标是循环一些关键值对 ')并最终不寻找循环。
var p ={"p1":"value1","p2":"value2","p3":"value3"}; if('p1' in p){ var val=p['p1']; ... }