如何遍历 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"
}
}
for (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]);
}
}
在 ECMAScript 5 下,您可以组合 Object.keys()
和 Array.prototype.forEach()
:
var obj = { first: "John", last: "Doe" }; // // 访问非继承的可枚举键 // Object.keys(obj).forEach(function(key) { console.log(key, obj[key]); });
for ... in ... hasOwnProperty
模式可以在任何东西上调用,据我所知(对象、数组、空、未定义、真、假、数字原语、对象)。
Object.keys()
,而是 forEach()
和对 .length
的重复访问!如果您改用经典的 for
循环,它的速度几乎是 Firefox 33 中的 for..in
+ hasOwnProperty()
的两倍。
keys
函数和 forEach
函数,它需要解析匿名函数,然后在 forEach 循环的每个元素上调用匿名函数。如果您了解编程,您就会明白所有这些解析和函数调用比 for 结构循环之类的本机解决方案花费的时间要多得多。
在 ES6/2015 中,您可以像这样循环访问对象(使用 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.
});
在 ES7/2016 中,您可以使用 Object.entries
而不是 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));
如果您还想遍历嵌套对象,可以使用递归函数 (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.
});
};
与上述函数相同,但使用 ES7 Object.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()
和 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.
})
);
另一种循环对象的方法是使用 for ... in 和 for ... of。请参阅vdegenne's nicely written answer。
这个问题
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]);
}
}
}
}
_.each(validation_messages, function(value, key){
_.each(value, function(value, key){
console.log(value);
});
});
如果你使用递归,你可以返回任何深度的对象属性——
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
}
*/
这个答案是这篇文章中提供的解决方案的集合,以及一些性能反馈。我认为有两个用例,OP 没有提到他是否需要访问密钥才能在循环过程中使用它们。
一、需要访问的密钥
✔ of
和 Object.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 在内部初始化了很多变量来构建这个过程(参见反馈以获取证据)。除非你不是在开发一个值得优化的大型应用程序,否则没关系,但如果优化是你的首要任务,你应该考虑一下。
二、我们只需要访问每个值
✔ of
和 Object.values
方法
let v;
for (v of Object.values(obj)) {
}
关于测试的更多反馈:
缓存 Object.keys 或 Object.values 性能可以忽略不计
例如,
const keys = Object.keys(obj);
let i;
for (i of keys) {
//
}
// same as
for (i of Object.keys(obj)) {
//
}
对于 Object.values 的情况,在 Firefox 中使用带有缓存变量的本机 for 循环似乎比使用 for...of 循环要快一些。但是,区别并不那么重要,Chrome 的 for...of 运行速度比原生 for 循环快,所以我建议在任何情况下(第 4 次和第 6 次测试)处理 Object.values 时使用 for...of。
在 Firefox 中,for...in 循环非常慢,所以当我们想在迭代期间缓存键时,最好使用 Object.keys。另外,Chrome 以相同的速度运行这两种结构(第一次和最后一次测试)。
您可以在此处查看测试:https://jsperf.com/es7-and-misc-loops
for(var k in validation_messages) {
var o = validation_messages[k];
do_something_with(o.your_name);
do_something_else_with(o.your_msg);
}
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 work
if (owns.call(obj, prop)) {
console.log(prop, "=", obj[prop]);
}
}
}
}
hasOwnProperty
存储在 owns
中,然后调用 owns.call(obj, prop)
而不是像 this answer 那样只调用 obj.hasOwnProperty(prop)
?
obj
可能在其自身上定义了 hasOwnProperty
函数,所以它不会使用来自 Object.prototype
的函数。您可以在 obj.hasOwnProperty = function(){return false;}
这样的 for
循环之前尝试,它不会遍历任何属性。
p 是值
for (var key in p) {
alert(key + ' => ' + p[key]);
}
或者
Object.keys(p).forEach(key => { console.log(key, p[key]) })
在 ES7 中,你可以这样做:
for (const [key, value] of Object.entries(obj)) {
//
}
for(var key in validation_messages){
for(var subkey in validation_messages[key]){
//code here
//subkey being value, key being 'yourname' / 'yourmsg'
}
}
有几种方法可以做到这一点...
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);
另外的选择:
var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
console.log(x);
}
这是 AgileJon 解决方案的改进和递归版本 (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);
该解决方案适用于各种不同的深度。
ECMAScript 2017,一个月前刚刚完成,引入了 Object.values()。所以现在你可以这样做:
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');
}
输出:
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"
我认为值得指出的是,jQuery 用 $.each()
很好地解决了这个问题。
请参阅:.each()
例子:
$('.foo').each(function() {
console.log($(this));
});
$(this)
是对象内的单个项目。如果您不想使用 jQuery 的选择器引擎,请将 $('.foo')
换成一个变量。
我无法让之前的回答完全符合我的要求。
在玩弄了这里的其他回复之后,我做了这个。这很hacky,但它有效!
对于这个对象:
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 = 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]));
要遍历 JavaScript 对象,我们可以使用 forEach 并优化代码,我们可以使用箭头函数。
使用 lodash _.forEach:
_.forEach({ 'a': 1, 'b': 2 }, function(value, key) { console.log(key, value); });
为每个2
(找到 here):
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);
}
}
}
});
}
使用 ES8 Object.entries() 应该是一种更紧凑的方式来实现这一点。
Object.entries(validation_messages).map(([key,object]) => {
alert(`Looping through key : ${key}`);
Object.entries(object).map(([token, value]) => {
alert(`${token} : ${value}`);
});
});
对我有用的解决方案如下:
_private.convertParams = function(params){
var params = [];
Object.keys(values).forEach(function(key) {
params.push({"id":key, "option":"Igual", "value":params[key].id})
});
return params;
}
奇特一号——深度穿越
JSON.stringify(validation_messages,(field,value)=>{
if(!field) return value;
// ... your code
return value;
})
在此解决方案中,我们使用 replacer 允许深度遍历整个对象和嵌套对象 - 在每个级别上,您将获得所有字段和值。如果您需要获取每个字段的完整路径,请查看 here。
var validation_messages = { "key_1": { "your_name": "jimmy", "your_msg": "hello world" }, "key_2": { "your_name": "billy", "your_msg": "foo 等于 bar", "deep": { "color": "red", "size": "10px" } } } JSON.stringify(validation_messages,(field,value)=>{ if(!field) 返回值;console.log(`键:${field.padEnd(11)} - 值:${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);
在我的情况下(基于上述),任何数量的级别都是可能的。
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"]
不定期副业成功案例分享
for in
与传统的foreach
非常相似。