从对象数组中提取属性值作为数组

1870

我有一个JavaScript对象数组,其结构如下:

objArray = [ { foo: 1, bar: 2}, { foo: 3, bar: 4}, { foo: 5, bar: 6} ];

我希望从每个对象中提取一个字段,并获取包含这些值的数组,例如字段foo将给出数组[ 1, 3, 5 ]

我可以使用以下简单方法来实现:

function getFields(input, field) {
    var output = [];
    for (var i=0; i < input.length ; ++i)
        output.push(input[i][field]);
    return output;
}

var result = getFields(objArray, "foo"); // returns [ 1, 3, 5 ]

有没有更优雅或成语化的方法来做这件事,以便不需要使用自定义实用函数?


关于建议复制问题的说明,它涵盖了如何将单个对象转换为数组。


4
Prototype库向Array原型添加了一个"pluck"函数(我想是这样),因此您可以编写var foos = objArray.pluck("foo"); - Pointy
3
好的,我会尽力进行翻译。以下是需要翻译的内容:@hyde - http://jsperf.com/map-vs-native-for-loop - 请看一下这个链接,希望纯粹的循环本身可以成为一个好的解决方案。 - N20084753
1
@N20084753,为了进行公平的测试,您还应该比较存在的本地Array.prototype.map函数。 - Alnitak
4
楼上的,我喜欢你提出的方法胜过其他提出的方法。没什么问题。 - user1017882
1
@Pointy,我想你在谈论的是函数_.pluck(objArray, "foo"),然而这是Underscore库的一部分。最好的方法是使用ES6中可用的.map - XAronX
显示剩余4条评论
25个回答

2556

这里有一种更简短的实现方式:

let result = objArray.map(a => a.foo);
OR
let result = objArray.map(({ foo }) => foo)

你还可以检查Array.prototype.map()


4
好的,这与另一个回答者totymedli的评论相同,但仍然比其他回答更好(在我看来),因此...将其更改为被接受的答案。 - hyde
2
我真的很喜欢那个,顺便说一句,那个 => 符号给我一种新鲜感,所以我认为如果这个解决方案实际可行,就需要重新审查它的兼容性。 - Paulo Roberto Rosa
7
箭头函数在除了 IE 以外的大部分环境中基本上都得到了支持。 - tgies
5
可以,但在我看来,除了使用一种当时不可用且某些浏览器甚至不支持的语法之外,没有任何东西使得这个答案客观上更好。我还想指出,这个答案是原先被接受的答案近一年前评论的直接复制。 - Alnitak
55
在我看来,使用更新的功能确实更好。这段代码非常常见,因此我不认为这是剽窃行为。将过时的答案固定在顶部并没有什么价值。 - Rob
显示剩余6条评论

738

是的,但它依赖于 JavaScript 的一个 ES5 特性。这意味着它在 IE8 或更早版本中将无法工作。

var result = objArray.map(function(a) {return a.foo;});

在支持ES6语法的JS解释器上,你可以使用箭头函数(arrow function)来简化代码:

var result = objArray.map(a => a.foo);

Array.prototype.map 文档


75

就JS-only解决方案而言,我发现,尽管可能不太优雅,但简单的索引式for循环比其它替代方式更高效。

从一个10万元素数组中提取单个属性(通过jsPerf)

传统的for循环 368次操作/秒

var vals=[];
for(var i=0;i<testArray.length;i++){
   vals.push(testArray[i].val);
}

ES6的for..of循环 303次操作/秒

var vals=[];
for(var item of testArray){
   vals.push(item.val); 
}

Array.prototype.map每秒19个操作

var vals = testArray.map(function(a) {return a.val;});

简而言之,.map()方法速度较慢,但如果您认为可读性比性能更重要,可以放心使用。

编辑#2:6/2019 - jsPerf链接已经失效,已删除。


4
我刚刚使用jsBench重新测试了一下(非常感谢Mirko Vukušić为jsPerf创建了一种替代方法),结果仍然是这样的,for最快,for .. of稍微慢一些,map大约慢了一半。 - Ivan Shatsky
它们对我来说与原始答案不同。在原始答案中,“for..of”速度约为“map”的16倍。今天运行基准测试,“for..of”速度约为“map”的2倍。 - Patrick
在性能考虑与代码可读性之间,这是一个非常有趣的观点,让我读了这篇文章,进一步阐明了这个主题。https://leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of/ - FreeSoftwareServers

58

请查看Lodash的_.pluck()函数或Underscore的_.pluck()函数。这两个函数都可以在一次函数调用中完成您想要的操作!

var result = _.pluck(objArray, 'foo');
更新:自 Lodash v4.0.0 起,_.pluck() 已被移除,推荐使用类似于 Niet's answer_.map()_.pluck() 仍可在 Underscore 中使用更新2:在评论中提到,在 Lodash v4 和 4.3 之间,添加了一个新函数以再次提供此功能。_.property() 是一个简写函数,返回一个获取对象属性值的函数。
此外,_.map() 现在允许将字符串作为第二个参数传递,该参数被传递到 _.property() 中。因此,以下两行代码与 Lodash 4 之前的示例代码等效。
var result = _.map(objArray, 'foo');
var result = _.map(objArray, _.property('foo'));

_.property(),因此_.map(),还允许您提供一个点分隔的字符串或数组,以便访问子属性:

var objArray = [
    {
        someProperty: { aNumber: 5 }
    },
    {
        someProperty: { aNumber: 2 }
    },
    {
        someProperty: { aNumber: 9 }
    }
];
var result = _.map(objArray, _.property('someProperty.aNumber'));
var result = _.map(objArray, _.property(['someProperty', 'aNumber']));

上面示例中的两个_.map()调用都将返回[5, 2, 9]

如果您对函数式编程有更深入的了解,请看看RamdaR.pluck()函数,它可能如下所示:

var result = R.pluck('foo')(objArray);  // or just R.pluck('foo', objArray)

45

从对象数组中收集不同字段的示例

let inputArray = [
  { id: 1, name: "name1", value: "value1" },
  { id: 2, name: "name2", value: "value2" },
];

let ids = inputArray.map( (item) => item.id);
let names = inputArray.map((item) => item.name);
let values = inputArray.map((item) => item.value);

console.log(ids);
console.log(names);
console.log(values);

结果:

[ 1, 2 ]
[ 'name1', 'name2' ]
[ 'value1', 'value2' ]

24

最好使用像lodash或underscore这样的库来保证跨浏览器的稳定性。

在Lodash中,您可以通过以下方法获取数组中属性的值

_.map(objArray,"foo")

在 Underscore 中

_.pluck(objArray,"foo")

都将返回

[1, 2, 3]

19

使用Array.prototype.map

function getFields(input, field) {
    return input.map(function(o) {
        return o[field];
    });
}

请参见上面的链接,以获取用于早期ES5浏览器的 shim。

17

在ES6中,你可以这样做:

const objArray = [{foo: 1, bar: 2}, {foo: 3, bar: 4}, {foo: 5, bar: 6}]
objArray.map(({ foo }) => foo)

12

如果你想在ES6+中拥有多个值,以下方法可行:

objArray = [ { foo: 1, bar: 2, baz: 9}, { foo: 3, bar: 4, baz: 10}, { foo: 5, bar: 6, baz: 20} ];

let result = objArray.map(({ foo, baz }) => ({ foo, baz }))

这个语句中左边的{foo, baz}使用了对象解构,而箭头函数右侧的表达式相当于{foo: foo, baz: baz},这归功于ES6的增强对象字面量


10
以上答案适用于单个属性,但若要从数组中选择多个属性,请使用以下方法。
var arrayObj=[{Name,'A',Age:20,Email:'a.gmail.com'},{Name,'B',Age:30,Email:'b.gmail.com'},{Name,'C',Age:40,Email:'c.gmail.com'}]

现在我只选择了两个字段

 var outPutArray=arrayObj.map(( {Name,Email} ) =>  ({Name,Email}) )
 console.log(outPutArray)

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