如何循环使用对象作为成员的普通JavaScript对象

如何遍历JavaScript对象中的所有成员,包括作为对象的值?

例如,我如何遍历这个(访问每个的“your_name”和“your_message”)?

var validation_messages = {"key_1": {"your_name": "jimmy","your_msg": "hello world"},"key_2": {"your_name": "billy","your_msg": "foo equals bar"}}
1971578 次浏览
for(var k in validation_messages) {var o = validation_messages[k];do_something_with(o.your_name);do_something_else_with(o.your_msg);}
for (var key in validation_messages) {// skip loop if the property is from prototypeif (!validation_messages.hasOwnProperty(key)) continue;
var obj = validation_messages[key];for (var prop in obj) {// skip loop if the property is from prototypeif (!obj.hasOwnProperty(prop)) continue;
// your codealert(prop + " = " + obj[prop]);}}
for(var key in validation_messages){for(var subkey in validation_messages[key]){//code here//subkey being value, key being 'yourname' / 'yourmsg'}}

如果您使用递归,您可以返回任何深度的对象属性-

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 key in validation_messages) {var obj = validation_messages[key];for (var prop in obj) {alert(prop + " = " + obj[prop]);}}

您还将循环遍历原始对象的原型。

有了这个,你就可以避免它:

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

在ECMAScript 5下,您可以组合Object.keys()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]);
});

AgileJon回答的优化和改进版本:

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 workif (owns.call(obj, prop)) {console.log(prop, "=", obj[prop]);}}}}

使用Underscore.js#0

_.each(validation_messages, function(value, key){_.each(value, function(value, key){console.log(value);});});

我无法得到以前的答案来做我所追求的事情。

在这里玩了其他回复之后,我做了这个。这很奇怪,但它有效!

对于这个对象:

var myObj = {pageURL    : "BLAH",emailBox   : {model:"emailAddress", selector:"#emailAddress"},passwordBox: {model:"password"    , selector:"#password"}};

…此代码:

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

…在控制台中生成:

myObj.pageURL = BLAHmyObj.emailBox.model = emailAddressmyObj.emailBox.selector = #emailAddressmyObj.passwordBox.model = passwordmyObj.passwordBox.selector = #password

在我的情况下(在前面的基础上),任何数量的级别都是可能的。

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

结果:

["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"]

以下是AgileJon解决方案的改进和递归版本(demo):

function loopThrough(obj){for(var key in obj){// skip loop if the property is from prototypeif(!obj.hasOwnProperty(key)) continue;
if(typeof obj[key] !== 'object'){//your codeconsole.log(key+" = "+obj[key]);} else {loopThrough(obj[key]);}}}loopThrough(validation_messages);

这个解决方案适用于各种不同的深度。

另一种选择:

var testObj = {test: true, test1: false};for(let x of Object.keys(testObj)){console.log(x);}

ES6/2015中,您可以循环遍历这样的对象(使用箭头函数):

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

ES7/2016中,您可以使用#0而不是Object.keys并循环遍历这样的对象:

Object.entries(myObj).forEach(([key, val]) => {console.log(key); // the name of the current key.console.log(val); // the value of the current key.});

上面的也可以作为单行

Object.entries(myObj).forEach(([key, val]) => console.log(key, val));

jsbin

如果你也想遍历嵌套对象,你可以使用递归函数(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

与上面的函数相同,但使用ES7Object.entries()而不是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.});};

在这里,我们循环遍历嵌套对象的更改值,并使用Object.entries()结合#1ES10/2019)一次性返回一个新对象:

const loopNestedObj = obj =>Object.fromEntries(Object.entries(obj).map(([key, val]) => {if (val && typeof val === "object") [key, loopNestedObj(val)]; // recurseelse [key, updateMyVal(val)]; // or do something with key and val.}));

另一种遍历对象的方法是使用为…在为…的。参见Vdegenne写得很好的回答

我认为值得指出的是,jQuery用$.each()很好地解决了这个问题。

见:. each()

示例:

$('.foo').each(function() {console.log($(this));});

$(this)是对象中的单个项目。如果您不想使用jQuery的选择器引擎,请将$('.foo')交换为变量。

ECMAScript 2017,一个月前刚刚完成,引入了Object.values()。所以现在你可以这样做:

let v;for (v of Object.values(validation_messages))console.log(v.your_name);   // jimmy billy

在ES7中,您可以:

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

此答案是本文中提供的解决方案的集合用一些性能反馈的帖子。我想有两个用例和OP没有提到他是否需要访问密钥才能使用它们在循环过程中。

I.需要访问密钥

ofObject.keys方法

let k;for (k of Object.keys(obj)) {
/*        k : key*   obj[k] : value*/}

in方法

let k;for (k in obj) {
/*        k : key*   obj[k] : value*/}

谨慎使用这个,因为它可以打印obj的原型属性

✔ES7方法

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

然而,在编辑时,我不推荐ES7方法,因为JavaScript在内部初始化了很多变量来构建这个过程(参见反馈以获得证明)。除非你不是在开发一个值得优化的大型应用程序,否则没关系,但如果优化是你的首要任务,你应该考虑一下。

二、我们只需要访问每个值

ofObject.values方法

let v;for (v of Object.values(obj)) {
}

关于测试的更多反馈:

  • 缓存Object.keysObject.values的性能可以忽略不计

例如,

const keys = Object.keys(obj);let i;for (i of keys) {//}// same asfor (i of Object.keys(obj)) {//}
  • 对于Object.values情况,在Firefox中使用带有缓存变量的本机for循环似乎比使用for...of循环快一点。然而,区别并不重要,Chrome运行for...of比本机for循环快,所以我建议在任何情况下处理Object.values时使用for...of(第4次和第6次测试)。

  • 在Firefox中,for...in循环非常慢,所以当我们想在迭代期间缓存键时,最好使用Object.keys。另外Chrome以相同的速度运行两个结构(第一次和最后一次测试)。

您可以在此处查看测试:https://jsperf.com/es7-and-misc-loops

p是值

for (var key in p) {alert(key + ' => ' + p[key]);}

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

对我有效的解决方案如下:

_private.convertParams = function(params){var params = [];Object.keys(values).forEach(function(key) {params.push({"id":key, "option":"Igual", "value":params[key].id})});return params;}

var obj = {name: "SanD",age: "27"}Object.keys(obj).forEach((key) => console.log(key,obj[key]));

为了遍历JavaScript对象,我们可以使用for每个,为了优化代码,我们可以使用箭头函数。

有几种方法可以做到这一点…

1)两层for… in循环…

for (let key in validation_messages) {const vmKeys = validation_messages[key];for (let vmKey in vmKeys) {console.log(vmKey + vmKeys[vmKey]);}}

2)使用Object.key

Object.keys(validation_messages).forEach(key => {const vmKeys = validation_messages[key];Object.keys(vmKeys).forEach(key => {console.log(vmKeys + vmKeys[key]);});});

3)递归函数

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

并称其为:

recursiveObj(validation_messages);

异国情调-深遍历

JSON.stringify(validation_messages,(field,value)=>{if(!field) return value;
// ... your code
return value;})

在这个解决方案中,我们使用替代品,它允许深入遍历整个对象和嵌套对象-在每个级别上,您将获得所有字段和值。如果您需要获得每个字段的完整路径,请查看这里

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

使用ES8Object.entries()应该是实现这一目标的更紧凑的方法。

Object.entries(validation_messages).map(([key,object]) => {
alert(`Looping through key : ${key}`);
Object.entries(object).map(([token, value]) => {alert(`${token} : ${value}`);});});

在2020年你想要不可变和通用函数

这将遍历由子对象、数组和字符串组成的多维对象,并应用一个自定义函数:

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

用法:

const r = iterate(data, e=>'converted_'+e);console.log(r);

forEach2

(找到这里):

var lunch = {sandwich: 'ham',age: 48,};lunch.forEach2(function (item, key) {console.log(key);console.log(item);});

代码:

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

产出:

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"

使用Lodash_

_.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>

遍历对象的方法有很多种。请看下面的示例。

var obj = {'name':'John Doe','email':'johndoe@example.com'}

办法1

var keys = Object.keys(obj)for(var i= 0; i < keys.length;i++){console.log(keys[i]+ ': ' + obj[keys[i]])}

办法2

for(var key in obj){console.log(key+': '+ obj[key])}

办法3

Object.keys(obj).forEach(function (key) {console.log(key+ ': ' + obj[key])})