admin管理员组文章数量:1125782
How can I loop through all members in a JavaScript object, including values that are objects?
For example, how could I loop through this (accessing the "your_name" and "your_message" for each)?
var validation_messages = {
"key_1": {
"your_name": "jimmy",
"your_msg": "hello world"
},
"key_2": {
"your_name": "billy",
"your_msg": "foo equals bar"
}
}
How can I loop through all members in a JavaScript object, including values that are objects?
For example, how could I loop through this (accessing the "your_name" and "your_message" for each)?
var validation_messages = {
"key_1": {
"your_name": "jimmy",
"your_msg": "hello world"
},
"key_2": {
"your_name": "billy",
"your_msg": "foo equals bar"
}
}
Share
Improve this question
edited Jul 19, 2021 at 11:36
Peter Mortensen
31.6k22 gold badges109 silver badges133 bronze badges
asked May 28, 2009 at 16:18
edtedt
22.4k32 gold badges85 silver badges119 bronze badges
0
30 Answers
Reset to default 2262for (var key in validation_messages) {
// skip loop if the property is from prototype
if (!validation_messages.hasOwnProperty(key)) continue;
var obj = validation_messages[key];
for (var prop in obj) {
// skip loop if the property is from prototype
if (!obj.hasOwnProperty(prop)) continue;
// your code
alert(prop + " = " + obj[prop]);
}
}
Under ECMAScript 5, you can combine Object.keys()
and Array.prototype.forEach()
:
var obj = {
first: "John",
last: "Doe"
};
//
// Visit non-inherited enumerable keys
//
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
In ES6/2015 you can loop through an object like this (using the arrow function):
Object.keys(myObj).forEach(key => {
console.log(key); // the name of the current key.
console.log(myObj[key]); // the value of the current key.
});
JS Bin
In ES7/2016 you can use Object.entries
instead of Object.keys
and loop through an object like this:
Object.entries(myObj).forEach(([key, val]) => {
console.log(key); // the name of the current key.
console.log(val); // the value of the current key.
});
The above would also work as a one-liner:
Object.entries(myObj).forEach(([key, val]) => console.log(key, val));
jsbin
In case you want to loop through nested objects as well, you can use a recursive function (ES6):
const loopNestedObj = obj => {
Object.keys(obj).forEach(key => {
if (obj[key] && typeof obj[key] === "object") loopNestedObj(obj[key]); // recurse.
else console.log(key, obj[key]); // or do something with key and val.
});
};
JS Bin
The same as function above, but with ES7 Object.entries()
instead of Object.keys()
:
const loopNestedObj = obj => {
Object.entries(obj).forEach(([key, val]) => {
if (val && typeof val === "object") loopNestedObj(val); // recurse.
else console.log(key, val); // or do something with key and val.
});
};
Here we loop through nested objects change values and return a new object in one go using Object.entries()
combined with Object.fromEntries()
(ES10/2019):
const loopNestedObj = obj =>
Object.fromEntries(
Object.entries(obj).map(([key, val]) => {
if (val && typeof val === "object") [key, loopNestedObj(val)]; // recurse
else [key, updateMyVal(val)]; // or do something with key and val.
})
);
Another way of looping through objects is by using for ... in and for ... of. See vdegenne's nicely written answer.
The problem with this
for (var key in validation_messages) {
var obj = validation_messages[key];
for (var prop in obj) {
alert(prop + " = " + obj[prop]);
}
}
is that you’ll also loop through the primitive object's prototype.
With this one you will avoid it:
for (var key in validation_messages) {
if (validation_messages.hasOwnProperty(key)) {
var obj = validation_messages[key];
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
alert(prop + " = " + obj[prop]);
}
}
}
}
Using Underscore.js’s _.each
:
_.each(validation_messages, function(value, key){
_.each(value, function(value, key){
console.log(value);
});
});
This answer is an aggregate of the solutions that were provided in this post with some performance feedbacks. I think there is two use cases and the OP didn't mention if he needs to access the keys in order use them during the loop process.
I. The keys need to be accessed
✔ The of
and Object.keys
approach
let k;
for (k of Object.keys(obj)) {
/* k : key
* obj[k] : value
*/
}
✔ The in
approach
let k;
for (k in obj) {
/* k : key
* obj[k] : value
*/
}
Use this one with caution, as it could print prototype'd properties of obj
✔ The ES7 approach
for (const [key, value] of Object.entries(obj)) {
}
However, at the time of the edit I wouldn't recommend the ES7 method, because JavaScript initializes a lot of variables internally to build this procedure (see the feedbacks for proof). Unless you are not developing a huge application which deserves optimization, then it is OK, but if optimization is your priority, you should think about it.
II. We just need to access each value
✔ The of
and Object.values
approach
let v;
for (v of Object.values(obj)) {
}
More feedbacks about the tests:
- Caching
Object.keys
orObject.values
performance is negligible
For instance,
const keys = Object.keys(obj);
let i;
for (i of keys) {
//
}
// same as
for (i of Object.keys(obj)) {
//
}
For
Object.values
case, using a nativefor
loop with cached variables in Firefox seems to be a little faster than using afor...of
loop. However, the difference is not that important and Chrome is runningfor...of
faster than nativefor
loop, so I would recommend to usefor...of
when dealing withObject.values
in any cases (4th and 6th tests).In Firefox, the
for...in
loop is really slow, so when we want to cache the key during the iteration it is better to useObject.keys
. Plus Chrome is running both structure at equal speed (first and last tests).
You can check the tests here: https://jsperf.com/es7-and-misc-loops
If you use recursion you can return object properties of any depth-
function lookdeep(object){
var collection= [], index= 0, next, item;
for(item in object){
if(object.hasOwnProperty(item)){
next= object[item];
if(typeof next== 'object' && next!= null){
collection[index++]= item +
':{ '+ lookdeep(next).join(', ')+'}';
}
else collection[index++]= [item+':'+String(next)];
}
}
return collection;
}
//example
var O={
a:1, b:2, c:{
c1:3, c2:4, c3:{
t:true, f:false
}
},
d:11
};
var lookdeepSample= 'O={'+ lookdeep(O).join(',\n')+'}';
/* returned value: (String)
O={
a:1,
b:2,
c:{
c1:3, c2:4, c3:{
t:true, f:false
}
},
d:11
}
*/
for(var k in validation_messages) {
var o = validation_messages[k];
do_something_with(o.your_name);
do_something_else_with(o.your_msg);
}
An optimized and improved version of AgileJon's answer:
var key, obj, prop, owns = Object.prototype.hasOwnProperty;
for (key in validation_messages ) {
if (owns.call(validation_messages, key)) {
obj = validation_messages[key];
for (prop in obj ) {
// Using obj.hasOwnProperty might cause you headache if there is
// obj.hasOwnProperty = function(){return false;}
// but 'owns' will always work
if (owns.call(obj, prop)) {
console.log(prop, "=", obj[prop]);
}
}
}
}
p is the value
for (var key in p) {
alert(key + ' => ' + p[key]);
}
OR
Object.keys(p).forEach(key => { console.log(key, p[key]) })
In ES7 you can do:
for (const [key, value] of Object.entries(obj)) {
//
}
There are so many ways to traverse an object. Please have a look at below examples.
var obj = {'name':'John Doe','email':'[email protected]'}
Approach 1
var keys = Object.keys(obj)
for(var i= 0; i < keys.length;i++){
console.log(keys[i]+ ': ' + obj[keys[i]])
}
Approach 2
for(var key in obj){
console.log(key+': '+ obj[key])
}
Approach 3
Object.keys(obj).forEach(function (key) {
console.log(key+ ': ' + obj[key])
})
for(var key in validation_messages){
for(var subkey in validation_messages[key]){
//code here
//subkey being value, key being 'yourname' / 'yourmsg'
}
}
A few ways to do that...
1) A two-layer for...in loop...
for (let key in validation_messages) {
const vmKeys = validation_messages[key];
for (let vmKey in vmKeys) {
console.log(vmKey + vmKeys[vmKey]);
}
}
2) Using Object.key
Object.keys(validation_messages).forEach(key => {
const vmKeys = validation_messages[key];
Object.keys(vmKeys).forEach(key => {
console.log(vmKeys + vmKeys[key]);
});
});
3) Recursive function
const recursiveObj = obj => {
for(let key in obj){
if(!obj.hasOwnProperty(key)) continue;
if(typeof obj[key] !== 'object'){
console.log(key + obj[key]);
} else {
recursiveObj(obj[key]);
}
}
}
And call it like:
recursiveObj(validation_messages);
Another option:
var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
console.log(x);
}
Here comes the improved and recursive version of AgileJon's solution (demo):
function loopThrough(obj){
for(var key in obj){
// skip loop if the property is from prototype
if(!obj.hasOwnProperty(key)) continue;
if(typeof obj[key] !== 'object'){
//your code
console.log(key+" = "+obj[key]);
} else {
loopThrough(obj[key]);
}
}
}
loopThrough(validation_messages);
This solution works for all kinds of different depths.
ECMAScript 2017, just finalized a month ago, introduces Object.values(). So now you can do this:
let v;
for (v of Object.values(validation_messages))
console.log(v.your_name); // jimmy billy
var validation_messages = {
"key_1": {
"your_name": "jimmy",
"your_msg": "hello world"
},
"key_2": {
"your_name": "billy",
"your_msg": "foo equals bar"
}
}
for (var i in validation_messages) {
console.log("i = \"" + i + "\"");
console.log("validation_messages[\"" + i + "\"] = ");
console.log(validation_messages[i]);
console.log("\n");
for (var j in validation_messages[i]) {
console.log("j = \"" + j + "\"");
console.log("validation_messages[\"" + i + "\"][\"" + j + "\"] = \"" + validation_messages[i][j] + "\"");
console.log("\n");
}
console.log('\n');
}
Outputs:
i = "key_1"
validation_messages["key_1"] =
{
your_name:"jimmy",
your_msg:"hello world"
}
j = "your_name"
validation_messages["key_1"]["your_name"] = "jimmy"
j = "your_msg"
validation_messages["key_1"]["your_msg"] = "hello world"
i = "key_2"
validation_messages["key_2"] =
{
your_name:"billy",
your_msg:"foo equals bar"
}
j = "your_name"
validation_messages["key_2"]["your_name"] = "billy"
j = "your_msg"
validation_messages["key_2"]["your_msg"] = "foo equals bar"
I think it's worth pointing out that jQuery sorts this out nicely with $.each()
.
See: .each()
Example:
$('.foo').each(function() {
console.log($(this));
});
$(this)
being the single item inside the object. Swap $('.foo')
to a variable if you don't want to use jQuery's selector engine.
I couldn't get the previous answere to do quite what I was after.
After playing around with the other replies here, I made this. It's hacky, but it works!
For this object:
var myObj = {
pageURL : "BLAH",
emailBox : {model:"emailAddress", selector:"#emailAddress"},
passwordBox: {model:"password" , selector:"#password"}
};
... this code:
// Get every value in the object into a separate array item ...
function buildArray(p_MainObj, p_Name) {
var variableList = [];
var thisVar = "";
var thisYes = false;
for (var key in p_MainObj) {
thisVar = p_Name + "." + key;
thisYes = false;
if (p_MainObj.hasOwnProperty(key)) {
var obj = p_MainObj[key];
for (var prop in obj) {
var myregex = /^[0-9]*$/;
if (myregex.exec(prop) != prop) {
thisYes = true;
variableList.push({item:thisVar + "." + prop,value:obj[prop]});
}
}
if ( ! thisYes )
variableList.push({item:thisVar,value:obj});
}
}
return variableList;
}
// Get the object items into a simple array ...
var objectItems = buildArray(myObj, "myObj");
// Now use them / test them etc... as you need to!
for (var x=0; x < objectItems.length; ++x) {
console.log(objectItems[x].item + " = " + objectItems[x].value);
}
... produces this in the console:
myObj.pageURL = BLAH
myObj.emailBox.model = emailAddress
myObj.emailBox.selector = #emailAddress
myObj.passwordBox.model = password
myObj.passwordBox.selector = #password
var obj = {
name: "SanD",
age: "27"
}
Object.keys(obj).forEach((key) => console.log(key,obj[key]));
To loop through the JavaScript Object we can use forEach and to optimize the code we can use the arrow function.
using lodash _.forEach:
_.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
console.log(key, value);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
In 2023+ you want immutable and universal functions
This walks through your multidimensional object composed of sub-objects, arrays and string and apply a custom function:
export const iterate = (object, func) => {
const entries = Object.entries(object).map(([key, value]) =>
Array.isArray(value)
? [key, value.map(e => iterate(e, func))]
: typeof value === 'object'
? [key, iterate(value, func)]
: [key, func(value)]
);
return Object.fromEntries(entries);
};
Usage:
const r = iterate(data, e=>'converted_'+e);
console.log(r);
forEach2
(Found here):
var lunch = {
sandwich: 'ham',
age: 48,
};
lunch.forEach2(function (item, key) {
console.log(key);
console.log(item);
});
Code:
if (!Object.prototype.forEach2) {
Object.defineProperty(Object.prototype, 'forEach2', {
value: function (callback, thisArg) {
if (this == null) {
throw new TypeError('Not an object');
}
thisArg = thisArg || window;
for (var key in this) {
if (this.hasOwnProperty(key)) {
callback.call(thisArg, this[key], key, this);
}
}
}
});
}
Using ES8 Object.entries() should be a more compact way to achieve this.
Object.entries(validation_messages).map(([key,object]) => {
alert(`Looping through key : ${key}`);
Object.entries(object).map(([token, value]) => {
alert(`${token} : ${value}`);
});
});
The solution that works for me is the following:
_private.convertParams = function(params){
var params = [];
Object.keys(values).forEach(function(key) {
params.push({"id":key, "option":"Igual", "value":params[key].id})
});
return params;
}
Exotic one - deep traverse
JSON.stringify(validation_messages,(field,value)=>{
if(!field) return value;
// ... your code
return value;
})
In this solution we use replacer which allows to deep traverse the whole object and nested objects - on each level you will get all fields and values. If you need to get the full path to each field, look here.
var validation_messages = {
"key_1": {
"your_name": "jimmy",
"your_msg": "hello world"
},
"key_2": {
"your_name": "billy",
"your_msg": "foo equals bar",
"deep": {
"color": "red",
"size": "10px"
}
}
}
JSON.stringify(validation_messages,(field,value)=>{
if(!field) return value;
console.log(`key: ${field.padEnd(11)} - value: ${value}`);
return value;
})
var validation_messages = {
"key_1": {
"your_name": "jimmy",
"your_msg": "hello world"
},
"key_2": {
"your_name": "billy",
"your_msg": "foo equals bar"
}
}
for ( const item in validation_messages ) {
console.log( item )
console.log( validation_messages[item]["your_name"] )
console.log( validation_messages[item]["your_msg"] )
console.log( '---')
}
I recently tackled a similar question a few days back. I encourage readers to check it out to gain an understanding of the concepts discussed in this answer. Additionally, I've utilized data from that question.
import { ArrayQueue } from "@ut8pia/classifier/queue/ArrayQueue.js";
import { Path } from "@ut8pia/fluent/util/Path.js";
import assert from "assert";
const root = {
name: 'root',
children: [
{name: 'Child 1',
children: [
{ name: 'Child 1.1', children: [] },
{ name: 'Child 1.2', children: [
{ name: 'Child 1.2.1', children: [] },
{ name: 'Child 1.2.2', children: [] },
{ name: 'Child 1.2.3', children: [] }
]}
]},
{name: 'Child 2', children: [
{ name: 'Child 2.1', children: [] },
{ name: 'Child 2.2', children: [] },
]},
{ name: 'Child 3', children: [] }
]},
n = 11;
This time, however, we'll generate paths of properties as entries [name, value]
instead of paths of objects in the tree. Since each object stores two inner properties
{name: ..., children: ...}
each object yields 3 properties: the outer property storing the object itself and the two inner ones. Consequently, we anticipate n * 3
properties, which also equals the expected count of property paths.
const
np = n * 3
Unlike before, where the children objects of each object within the tree were explicitly outlined by the children
property, this time, defining the children of each property in the tree requires explicit specification.
const children = ([name, obj]) => !(obj instanceof Object)? []
: typeof(obj) === 'function'? []
: Array.isArray(obj)? obj.map((item, i) => [i, item])
: Object.entries(obj);
Conceptually, however, the challenge of navigating through all the properties in the tree mirrors precisely the task of traversing all the objects within the tree. This correspondence becomes evident when examining the code.
const
space = path => path.across(children(path.last)),
search = new ArrayQueue()
.let(Path.of([undefined, root]))
.search(space)
You can validate the proposed solution by:
const
assert.equal(search.toArray().length, np)
In my case (on the basis of the preceding) it is possible for any number of levels.
var myObj = {
rrr: undefined,
pageURL : "BLAH",
emailBox : {model:"emailAddress", selector:"#emailAddress"},
passwordBox: {model:"password" , selector:"#password"},
proba: {odin:{dva:"rr",trr:"tyuuu"}, od:{ff:5,ppa:{ooo:{lll:'lll'}},tyt:'12345'}}
};
function lookdeep(obj,p_Name,gg){
var A=[], tem, wrem=[], dd=gg?wrem:A;
for(var p in obj){
var y1=gg?'':p_Name, y1=y1 + '.' + p;
if(obj.hasOwnProperty(p)){
var tem=obj[p];
if(tem && typeof tem=='object'){
a1=arguments.callee(tem,p_Name,true);
if(a1 && typeof a1=='object'){for(i in a1){dd.push(y1 + a1[i])};}
}
else{
dd.push(y1 + ':' + String(tem));
}
}
};
return dd
};
var s=lookdeep(myObj,'myObj',false);
for (var x=0; x < s.length; ++x) {
console.log(s[x]+'\n');}
Result:
["myObj.rrr:undefined",
"myObj.pageURL:BLAH",
"myObj.emailBox.model:emailAddress",
"myObj.emailBox.selector:#emailAddress",
"myObj.passwordBox.model:password",
"myObj.passwordBox.selector:#password",
"myObj.proba.odin.dva:rr",
"myObj.proba.odin.trr:tyuuu",
"myObj.proba.od.ff:5",
"myObj.proba.od.ppa.ooo.lll:lll",
"myObj.proba.od.tyt:12345"]
本文标签:
版权声明:本文标题:How to loop through a plain JavaScript object with the objects as members - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736662842a1946503.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论