var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};
我如何循环遍历所有 p
元素 (p1
、p2
、p3
...) 并获取它们的键和值?var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};
我如何循环遍历所有 p
元素 (p1
、p2
、p3
...) 并获取它们的键和值?for-in
循环。然而,你还需要确保获得的键是对象实际的属性,而不是来自原型。
Here is the snippet:
var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};
for (var key in p) {
if (p.hasOwnProperty(key)) {
console.log(key + " -> " + p[key]);
}
}
使用 Object.keys() 代替 for-of:
var p = {
0: "value1",
"b": "value2",
key: "value3"
};
for (var key of Object.keys(p)) {
console.log(key + " -> " + p[key])
}
注意使用for-of
来替代for-in
,否则在命名属性上将返回undefined,Object.keys()
可确保只使用对象自身的属性而非整个原型链的属性。
使用新的Object.entries()
方法:
注意:该方法在Internet Explorer中不受本地支持,您可以考虑为旧版浏览器使用Polyfill。
const p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};
for (const [key, value] of Object.entries(p)) {
console.log(`${key}: ${value}`);
}
在ECMAScript 5中,您可以结合使用Object.keys()
和Array.prototype.forEach()
:
var obj = { first: "John", last: "Doe" };
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
ECMAScript 6 增加了 for...of
:
for (const key of Object.keys(obj)) {
console.log(key, obj[key]);
}
ECMAScript 8 添加了 Object.entries()
,避免了需要在原始对象中查找每个值的情况:
Object.entries(obj).forEach(
([key, value]) => console.log(key, value)
);
您可以结合使用for...of
、解构和Object.entries
:
for (const [key, value] of Object.entries(obj)) {
console.log(key, value);
}
Object.keys()
和 Object.entries()
的迭代顺序与 for...in
循环相同,但忽略原型链 。只迭代对象自身的可枚举属性。
Object.forEach(obj, function (value, key) {...})
?:( 当然,obj.forEach(function...)
更短并且与Array.prototype.forEach
相辅相成,但这可能会导致对象定义自己的forEach
属性。我想Object.keys
可以防止回调修改对象的键。 - David HarknesshasOwnProperty
方法来确定迭代中当前属性是否真正属于你正在检查的对象的属性: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
}
continue
周围的括号,它们是多余的。 - SystemicPlural{ }
,因为没有它们的 if
语句会让人难以理解哪些部分属于 if
语句的一部分,哪些不是。但我想这只是个人观点 :) - pimvdb{}
,主要是为了避免混淆,如果以后需要向 if
作用域中添加内容,使用 {}
可以更加清晰明了。 - Andreas Grech如果我们不提及循环对象的替代方法,这个问题就不完整了。
现在许多知名的JavaScript库都提供了自己的迭代集合方法,即针对数组、对象和类数组对象。这些方法方便易用,并且与任何浏览器完全兼容。
如果你使用 jQuery ,可以使用 jQuery.each()
方法。它可无缝地遍历对象和数组:
$.each(obj, function(key, value) {
console.log(key, value);
});
在 Underscore.js 中,您可以找到方法_.each()
,它遍历元素列表,并将每个元素依次提供给提供的函数进行处理(注意在 iteratee 函数中参数的顺序!):
_.each(obj, function(value, key) {
console.log(key, value);
});
Lo-Dash提供了几种迭代对象属性的方法。基本的_.forEach()
(或其别名_.each()
)可用于循环遍历对象和数组,但是(!)拥有length
属性的对象被视为数组,并且为了避免这种行为,建议使用_.forIn()
和_.forOwn()
方法(这些方法也具有将value
参数放在第一位的特点):
_.forIn(obj, function(value, key) {
console.log(key, value);
});
_.forIn()
迭代对象的自有和继承可枚举属性,而_.forOwn()
仅迭代对象的自有属性(基本上是针对hasOwnProperty
函数进行检查)。对于简单对象和对象字面量,这些方法都可以很好地工作。
通常,所有描述的方法在使用任何提供的对象时都具有相同的行为。除了使用原生的for..in
循环通常比任何抽象,例如jQuery.each()
更快,这些方法更易于使用,需要更少的编码并提供更好的错误处理。
前言:
在2018年,你遍历一个对象属性的选项如下(列表后面跟着一些例子):
for-in
[MDN, 规范] — 循环结构,循环遍历一个对象的可枚举属性(包括继承的属性),其名称为字符串。Object.keys
[MDN, 规范] — 函数提供一个数组,其中包含一个对象的自身和可枚举属性的名称,这些名称是字符串。Object.values
[MDN, 规范] — 函数提供一个数组,其中包含一个对象的自身和可枚举属性的值。Object.entries
[MDN, 规范] — 函数提供一个数组,其中包含一个对象的自身和可枚举属性的名称和值(数组中的每个条目都是一个[名称、值]
数组)。Object.getOwnPropertyNames
[MDN, 规范] — 函数提供一个数组,其中包含一个对象的自身属性的名称(即使是不可枚举的),这些名称是字符串。Object.getOwnPropertySymbols
[MDN, 规范] — 函数提供一个数组,其中包含一个对象的自身属性的名称(即使是不可枚举的),这些名称是符号。Reflect.ownKeys
[MDN, 规范] — 函数提供一个数组,其中包含一个对象的自身属性的名称(即使是不可枚举的),无论这些名称是字符串还是符号。Object.getPrototypeOf
[MDN,
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name in o) {
const value = o[name];
console.log(`${name} = ${value}`);
}
Object.keys
(使用for-of
循环,但您可以使用任何循环结构):
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.keys(o)) {
const value = o[name];
console.log(`${name} = ${value}`);
}
Object.values
:
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const value of Object.values(o)) {
console.log(`${value}`);
}
Object.entries
:
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const [name, value] of Object.entries(o)) {
console.log(`${name} = ${value}`);
}
Object.getOwnPropertyNames
:
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertyNames(o)) {
const value = o[name];
console.log(`${name} = ${value}`);
}
Object.getOwnPropertySymbols
:
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertySymbols(o)) {
const value = o[name];
console.log(`${String(name)} = ${value}`);
}
Reflect.ownKeys
:
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Reflect.ownKeys(o)) {
const value = o[name];
console.log(`${String(name)} = ${value}`);
}
所有属性,包括继承的不可枚举属性:
// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (let depth = 0, current = o; current; ++depth, current = Object.getPrototypeOf(current)) {
for (const name of Reflect.ownKeys(current)) {
const value = o[name];
console.log(`[${depth}] ${String(name)} = ${String(value)}`);
}
}
.as-console-wrapper {
max-height: 100% !important;
}
你可以像这样遍历它:
for (var key in p) {
alert(p[key]);
}
请注意,key
不会取得属性的值,它仅仅是一个索引值。
在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的兼容性表格中查看浏览器支持情况。
更新:
此问题的所有最流行情况的性能比较可在perfjs.info
上找到:对象字面量迭代
今天2020.03.06,我在MacOs High Sierra v10.13.6上测试了Chrome v80.0,Safari v13.0.5和Firefox 73.0.1上的选定解决方案。
for-in
(A,B)的解决方案对于所有浏览器的大型和小型对象都很快(或最快)for-of
(H)解决方案对于Chrome的小型和大型对象都很快i
(J,K)的解决方案对于所有浏览器的小对象都很快(对于Firefox也适用于大对象,但在其他浏览器上中等速度)执行性能测试的对象为:
下面的片段介绍了使用的解决方案
function A(obj,s='') {
for (let key in obj) if (obj.hasOwnProperty(key)) s+=key+'->'+obj[key] + ' ';
return s;
}
function B(obj,s='') {
for (let key in obj) s+=key+'->'+obj[key] + ' ';
return s;
}
function C(obj,s='') {
const map = new Map(Object.entries(obj));
for (let [key,value] of map) s+=key+'->'+value + ' ';
return s;
}
function D(obj,s='') {
let o = {
...obj,
*[Symbol.iterator]() {
for (const i of Object.keys(this)) yield [i, this[i]];
}
}
for (let [key,value] of o) s+=key+'->'+value + ' ';
return s;
}
function E(obj,s='') {
let o = {
...obj,
*[Symbol.iterator]() {yield *Object.keys(this)}
}
for (let key of o) s+=key+'->'+o[key] + ' ';
return s;
}
function F(obj,s='') {
for (let key of Object.keys(obj)) s+=key+'->'+obj[key]+' ';
return s;
}
function G(obj,s='') {
for (let [key, value] of Object.entries(obj)) s+=key+'->'+value+' ';
return s;
}
function H(obj,s='') {
for (let key of Object.getOwnPropertyNames(obj)) s+=key+'->'+obj[key]+' ';
return s;
}
function I(obj,s='') {
for (const key of Reflect.ownKeys(obj)) s+=key+'->'+obj[key]+' ';
return s;
}
function J(obj,s='') {
let keys = Object.keys(obj);
for(let i = 0; i < keys.length; i++){
let key = keys[i];
s+=key+'->'+obj[key]+' ';
}
return s;
}
function K(obj,s='') {
var keys = Object.keys(obj), len = keys.length, i = 0;
while (i < len) {
let key = keys[i];
s+=key+'->'+obj[key]+' ';
i += 1;
}
return s;
}
function L(obj,s='') {
Object.keys(obj).forEach(key=> s+=key+'->'+obj[key]+' ' );
return s;
}
function M(obj,s='') {
Object.entries(obj).forEach(([key, value]) => s+=key+'->'+value+' ');
return s;
}
function N(obj,s='') {
Object.getOwnPropertyNames(obj).forEach(key => s+=key+'->'+obj[key]+' ');
return s;
}
function O(obj,s='') {
Reflect.ownKeys(obj).forEach(key=> s+=key+'->'+obj[key]+' ' );
return s;
}
// TEST
var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};
let log = (name,f) => console.log(`${name} ${f(p)}`)
log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This snippet only presents choosen solutions
以下是在Chrome浏览器中测试小对象的结果:
for(key in p) {
alert( p[key] );
}
注意:您可以对数组执行此操作,但也会迭代 length
和其他属性。
var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); }
在警报中弹出“p1”和“p2”,那么有什么问题吗??? - Sebastian由于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}`);
}
for..in
+hasOwnProperty
稍微比较快(https://jsben.ch/pCDAk),而在超过几千个属性时,`Object.keys` 明显更快(https://jsben.ch/ptzsL)。 - jason.