![]() |
风流倜傥的葡萄酒 · 羅若翰神父街5日起開通連接高士德雅廉訪– ...· 2 周前 · |
![]() |
英姿勃勃的伤疤 · < 弋: ㄧˋ >辭典檢視- ...· 9 月前 · |
![]() |
慷慨大方的炒饭 · JS使用输入法在输入汉字时不统计拼音的字母数 ...· 12 月前 · |
![]() |
没人理的绿豆 · 孙尚鸿:内国法域外适用视域下的管辖权规则体系 ...· 12 月前 · |
![]() |
有情有义的卤蛋 · 让子弹飞(2010年姜文执导的电影)_搜狗百科· 1 年前 · |
我有一个具有以下结构的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 ]
有没有一种更优雅或更惯用的方式来做这件事,这样就不需要定制实用函数了?
关于 suggested duplicate 的说明,它涵盖了如何将单个对象转换为数组。
是的,但它依赖于JavaScript的ES5特性。这意味着它不能在IE8或更早的版本中工作。
var result = objArray.map(function(a) {return a.foo;});
在ES6兼容的JS解释器上,为了简洁起见,可以使用:
var result = objArray.map(a => a.foo);
function getFields(input, field) {
return input.map(function(o) {
return o[field];
}
有关ES5之前版本的浏览器的填充程序,请参阅上面的链接。
这取决于你对“更好”的定义。
其他答案指出了map的使用,这是自然的(特别是对于习惯于函数式风格的人)和简洁。我强烈建议您使用它(如果您不想为少数IE8- it人员所困扰)。因此,如果“更好”意味着“更简洁”、“可维护”、“可理解”,那么是的,它就更好了。
另一方面,这种美丽并不是没有额外的成本就能实现的。我不是microbench的狂热粉丝,但我放了一个小的 test here 。结果是可以预测的,旧的丑陋的方法似乎比map函数更快。因此,如果“更好”意味着“更快”,那么不,继续沿用传统的时尚。
同样,这只是一个微型工作台,并不是反对使用
map
,这只是我的两点意见:)。
在处理对象数组时,函数映射是一个很好的选择。尽管已经发布了一些很好的答案,但结合使用map和filter的示例可能会有所帮助。
如果要排除值未定义的属性或仅排除特定属性,可以执行以下操作:
var obj = {value1: "val1", value2: "val2", Ndb_No: "testing", myVal: undefined};
var keysFiltered = Object.keys(obj).filter(function(item){return !(item == "Ndb_No" || obj[item] == undefined)});
var valuesFiltered = keysFiltered.map(function(item) {return obj[item]});
虽然
map
是从对象列表中选择“列”的合适解决方案,但它也有缺点。如果不显式检查列是否存在,它将抛出一个错误,并(充其量)为您提供
undefined
。我会选择
reduce
解决方案,它可以简单地忽略该属性,甚至为您设置一个默认值。
function getFields(list, field) {
// reduce the provided list to an array only containing the requested field
return list.reduce(function(carry, item) {
// check if the item is actually an object and does contain the field
if (typeof item === 'object' && field in item) {
carry.push(item[field]);
// return the 'carry' (which is the list of matched field values)
return carry;
}, []);
}
即使所提供的列表中的某一项不是对象或不包含该字段,也可以这样做。
它甚至可以通过协商一个默认值来使其更加灵活,该默认值应该不是一个对象或不包含该字段。
function getFields(list, field, otherwise) {
// reduce the provided list to an array containing either the requested field or the alternative value
return list.reduce(function(carry, item) {
// If item is an object and contains the field, add its value and the value of otherwise if not
carry.push(typeof item === 'object' && field in item ? item[field] : otherwise);
// return the 'carry' (which is the list of matched field values)
return carry;
}, []);
}
这与map相同,因为返回的数组的长度与提供的数组的长度相同。(在这种情况下,
map
比
reduce
稍微便宜一点):
function getFields(list, field, otherwise) {
// map the provided list to an array containing either the requested field or the alternative value
return list.map(function(item) {
// If item is an object and contains the field, add its value and the value of otherwise if not
return typeof item === 'object' && field in item ? item[field] : otherwise;
}, []);
}
然后是最灵活的解决方案,它允许您简单地通过提供一个替代值在这两种行为之间切换。
function getFields(list, field, otherwise) {
// determine once whether or not to use the 'otherwise'
var alt = typeof otherwise !== 'undefined';
// reduce the provided list to an array only containing the requested field
return list.reduce(function(carry, item) {
// If item is an object and contains the field, add its value and the value of 'otherwise' if it was provided
if (typeof item === 'object' && field in item) {
carry.push(item[field]);
else if (alt) {
carry.push(otherwise);
// return the 'carry' (which is the list of matched field values)
return carry;
}, []);
}
由于上面的例子(希望)阐明了它的工作方式,让我们通过利用
Array.concat
函数来缩短该函数。
function getFields(list, field, otherwise) {
var alt = typeof otherwise !== 'undefined';
return list.reduce(function(carry, item) {
return carry.concat(typeof item === 'object' && field in item ? item[field] : (alt ? otherwise : []));
}, []);
}
这里有一个更简单的方法来实现它:
let result = objArray.map(a => a.foo);
或
let result = objArray.map(({ foo }) => foo)
您还可以查看
Array.prototype.map()
。
如果还希望支持类似数组的对象,请使用 Array.from (ES2015):
Array.from(arrayLike, x => x.foo);
与Array.prototype.map()方法相比,它的优点是输入也可以是一个集合
let arrayLike = new Set([{foo: 1}, {foo: 2}, {foo: 3}]);
如果您想在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}
使用的是
object destructoring
,而右侧的箭头由于使用了
ES6's enhanced object literals
,因此相当于
{foo: foo, baz: baz}
。
从对象数组中收集不同字段的示例
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' ]
map()
方法创建一个新数组,其中填充了对调用数组中的每个元素调用所提供函数的结果。
let kvArray = [{key: 1, value: 10},
{key: 2, value: 20},
{key: 3, value: 30}]
let reformattedArray = kvArray.map(obj => {
return obj.value
})
或
const kvArray = [['key1', 'value1'], ['key2', 'value2']]
// Use the regular Map constructor to transform a 2D key-value Array into a map
const myMap = new Map(kvArray)
myMap.get('key1') // returns "value1"
// Use Array.from() to transform a map into a 2D key-value Array
console.log(Array.from(myMap)) // Will show you exactly the same Array as kvArray
// A succinct way to do the same, using the spread syntax
console.log([...myMap])
// Or use the keys() or values() iterators, and convert them to an array