如何获取JavaScript对象的所有属性值(不知道键名)?

552
如果有一个 JavaScript 对象:
var objects={...};

假设一个对象拥有50个以上的属性,不知道这些属性名(也就是不知道'keys'),如何在循环中获取每个属性的值?


27
读者请注意:不要错过非常有见地的第二个答案 - Pandaiolo
可能是如何列出JavaScript对象的属性的重复问题。 - Nerdroid
25个回答

1154

根据需要支持的浏览器,有多种方法可以实现此操作。在野外的绝大多数浏览器都支持ECMAScript 5(ES5),但请注意,下面的许多示例使用Object.keys,该方法在IE < 9中不可用。请参阅兼容性表格

ECMAScript 3+

如果您需要支持旧版本的IE,则这是适合您的选项:

for (var key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
        var val = obj[key];
        // use val
    }
}

嵌套的if语句确保您不会枚举对象原型链中的属性(这几乎肯定是您想要的行为)。 您必须使用

Object.prototype.hasOwnProperty.call(obj, key) // ok

而不是

obj.hasOwnProperty(key) // bad

由于 ECMAScript 5+ 允许您使用 Object.create(null) 创建无原型的对象,这些对象将不具有 hasOwnProperty 方法。恶意代码还可能生成覆盖 hasOwnProperty 方法的对象。

ECMAScript 5+

您可以在支持 ECMAScript 5 及以上版本的任何浏览器中使用这些方法。它们从对象中获取值并避免枚举原型链。其中 obj 是您的对象:

var keys = Object.keys(obj);

for (var i = 0; i < keys.length; i++) {
    var val = obj[keys[i]];
    // use val
}

如果你想要更紧凑的东西或者想要小心处理循环中的函数,那么Array.prototype.forEach会是你的好朋友:

Object.keys(obj).forEach(function (key) {
    var val = obj[key];
    // use val
});
下一个方法构建包含对象值的数组。这对循环非常方便。
var vals = Object.keys(obj).map(function (key) {
    return obj[key];
});

// use vals array

如果你想使使用Object.keys的代码能够安全处理null(就像for-in循环一样),那么你可以这样做:Object.keys(obj || {})....

Object.keys返回可枚举属性。对于简单对象的迭代,这通常足够了。如果你需要处理具有不可枚举属性的对象,可以使用Object.getOwnPropertyNames代替Object.keys

ECMAScript 2015+(又名ES6)

在ECMAScript 2015中,数组更容易迭代。当您需要逐个处理值时,可以利用这一点:

for (const key of Object.keys(obj)) {
    const val = obj[key];
    // use val
}

使用ECMAScript 2015的箭头函数,将对象映射为值数组变成了一行代码:

const vals = Object.keys(obj).map(key => obj[key]);

// use vals array

ECMAScript 2015引入了Symbol,它的实例可用作属性名称。要获取对象的符号以进行枚举,请使用Object.getOwnPropertySymbols(此函数是为什么Symbol不能用于创建私有属性的原因)。来自ECMAScript2015的新Reflect API提供了Reflect.ownKeys,它返回一个包含属性名称(包括不可枚举的属性)和符号的列表。

数组推导式(不要尝试使用)

在ECMAScript 6发布之前,数组推导式被删除了。在它们被删除之前,解决方案如下:

const vals = [for (key of Object.keys(obj)) obj[key]];

// use vals array

ECMAScript 2017+

ECMAScript 2016新增的功能与此主题无关。ECMAScript 2017规范增加了Object.valuesObject.entries。两者都返回数组(与 Array.entries 的类比可能会令一些人感到惊讶)。Object.values可以直接使用或与for-of循环结合使用。

const values = Object.values(obj);

// use values array or:

for (const val of Object.values(obj)) {
    // use val
}

如果您想同时使用键和值,则可以使用Object.entries。它生成一个填满了[key, value]对的数组。您可以直接使用这个数组,或者(注意 ECMAScript 2015 的析构赋值)在for-of循环中使用:

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

Object.values替代方案

正如评论中和另一个答案的teh_senaus所提到的,使用这些方法之一作为替代方案可能是值得的。请不用担心,以下代码不会改变原型,它只是向Object添加了一个方法(这样做风险小得多)。使用箭头函数,这可以在一行代码中完成:

Object.values = obj => Object.keys(obj).map(key => obj[key]);
你现在可以像使用这样使用它。
// ['one', 'two', 'three']
var values = Object.values({ a: 'one', b: 'two', c: 'three' });

如果您想避免在本地 Object.values 存在时进行 shim,那么可以执行以下操作:

Object.values = Object.values || (obj => Object.keys(obj).map(key => obj[key]));

最后...

必须注意支持的浏览器/版本。上述内容仅在实现方法或语言特性时是正确的。例如,直到最近,支持ECMAScript 2015的V8默认关闭,这影响像Chrome这样的浏览器。应避免使用ECMAScript 2015中的功能,直到您打算支持的浏览器实现了您需要的功能。如果您使用Babel将代码编译为ECMAScript 5,则可以访问本答案中所有功能。


11
这个回答应该被接受(或者至少得到更多赞同),因为已经被接受的那个不完整(@olive指出了这一点)。 - 0xc0de
真遗憾,尽管有那么多所谓的技巧,我们仍然需要两次提到 obj。我猜创建一个帮助函数是不可避免的?就像 values(obj) 这样的东西。 - Steven Haryanto
任何这些方法都可以用作shim。例如: Object.values = obj => Object.keys(obj).map(key => obj[key]); - qubyte
1
ECMA 5的解决方案应该在所有现代浏览器中都能正常工作。ECMA 6尚未最终确定,在所有浏览器中的支持都是初步的。在Chrome中,ECMA 6部分实现但被禁用。在Firefox中,支持更好,但数组推导式是错误的(如上所述)。我认为我的将来时态使用会暗示这一点。@JacekLampart,哪个解决方案给你带来了错误? - qubyte
2
我无法想象为什么我们要等到ES2017才能获得Object.values()方法。 - Herbertusz
显示剩余12条评论

514

通过使用简单的for..in循环:

for(var key in objects) {
    var value = objects[key];
}

93
注意继承的原型对象的属性。参见:hasOwnProperty()。 - olive
117
如果您正在阅读这篇答案,您应该 绝对 阅读另一个答案 - mgarciaisaia
20
如果您正在阅读这个答案,可能正在处理字符串,那么您应该毫不犹豫地去抨击 JavaScript。 - user1228
1
如果你读了上面的答案,想要狠狠地打一顿JavaScript,那就试试lodash吧。 - slugmandrew
应该指出,这将不包括其enumerable标志设置为false的属性。这意味着您不会迭代任何类方法,但是您将迭代以其他方式创建的方法。 - rich remer

31
这是一个可重复使用的函数,用于将值放入数组中。它还考虑了原型。
Object.values = function (obj) {
    var vals = [];
    for( var key in obj ) {
        if ( obj.hasOwnProperty(key) ) {
            vals.push(obj[key]);
        }
    }
    return vals;
}

15
修改Object并不是什么大问题(Object.keys是一个常用的shim),你可能在考虑修改Object原型。 - sandstrom
你为什么需要使用hasOwnProperty()进行测试?如果对象没有该属性,如何在循环中迭代该键? - 1252748
4
谷歌一下@thomas,这很重要。它可能具有来自其原型链的属性。 - Joe

29
如果您可以访问Underscore.js,您可以像这样使用_.values函数:
_.values({one : 1, two : 2, three : 3}); // return [1, 2, 3]

@MathieuAmiot -- 你能解释一下吗? - Paden
lodash是一个与underscore兼容的替代品,速度更快。 - Mathieu Amiot
@Paden 这里有一个关于 SO 的相关问题:https://dev59.com/RmYr5IYBdhLWcg3wTYcQ - jichi
3
Lodash在这里是不必要的,会使你的代码体积变大。 - dman

15

ES5 Object.keys

var a = { a: 1, b: 2, c: 3 };
Object.keys(a).map(function(key){ return a[key] });
// result: [1,2,3]

3
为什么这个被踩了?我认为这是最简洁的解决方案之一。 - Sebastian Hojas
我不知道为什么这被踩了。这是在JS中最简单和最纯粹的解决方案,而且没有使用任何库或其他实用程序。 - sanjeev shetty
@sanjeevshetty Object.values 是更简单的解决方案。 - Unmitigated

14

如果你真的想要一个值数组,我发现这比使用for ... in循环构建一个数组更加简洁。

ECMA 5.1+

function values(o) { return Object.keys(o).map(function(k){return o[k]}) }

值得注意的是,在大多数情况下,您实际上并不需要一个值数组,这样做会更快:

for(var k in o) something(o[k]);

这会遍历对象o的键。在每次迭代中,k被设置为o的一个键。


9

const myObj = { a:1, b:2, c:3 }

获取所有值:

  • 最简洁的方式:

    • const myValues = Object.values(myObj)
  • const myValues = Object.keys(myObj).map(key => myObj[key])


6
您可以通过循环键来实现:
foo = {one:1, two:2, three:3};
for (key in foo){
    console.log("foo["+ key +"]="+ foo[key]);
}

将输出:

foo[one]=1
foo[two]=2
foo[three]=3

2
如果您想避免继承属性,还需要检查hasOwnProperty() - 0xc0de

5

请注意,此操作将不会返回继承的属性。 - rich remer

5
这个问题没有明确说明是否需要继承和不可枚举属性。
有一个获取所有内容(包括继承属性和不可枚举属性)的问题,谷歌很难找到。
如果我们要获取所有继承和不可枚举属性,我的解决方案是:
function getAllPropertyNames(obj) {
    let result = new Set();
    while (obj) {
        Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
        obj = Object.getPrototypeOf(obj);
    }
    return [...result];
}

然后遍历它们,只需使用for-of循环:

function getAllPropertyNames(obj) {
  let result = new Set();
  while (obj) {
    Object.getOwnPropertyNames(obj).forEach(p => result.add(p));
    obj = Object.getPrototypeOf(obj);
  }
  return [...result];
}

let obj = {
  abc: 123,
  xyz: 1.234,
  foobar: "hello"
};

for (p of getAllPropertyNames(obj)) console.log(p);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接