我有一个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 ]

是否有更优雅或更惯用的方法来实现这一点,从而不需要自定义实用程序函数?


注意建议的重复,它介绍了如何将单个对象转换为数组。


当前回答

查看Lodash的_.pulling()函数或Undercore的_.plus()函数。两者都可以在一个函数调用中实现您想要的功能!

var result = _.pluck(objArray, 'foo');

更新:从Lodash v4.0.0起,_.pulling()已被删除,支持_.map(),并与Niet的答案类似。pickle()在Undercore中仍然可用。

更新2:正如Mark在评论中指出的,在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]。

如果您对函数式编程有更多了解,请查看Ramda的R.pulp()函数,它看起来像这样:

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

其他回答

是的,但它依赖于JavaScript的ES5特性。这意味着它在IE8或更高版本中不起作用。

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

在ES6兼容的JS解释器上,为了简洁起见,可以使用箭头函数:

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

Array.prototype.map文档

从对象数组中解构并获取特定属性:

const customerList = dealerUserData?.partyDetails.map(
  ({ partyId, custAccountId }) => ({
    partyId,
    custAccountId,
    customerId: dealerUserData?._id,
    userId: dealerUserData?.authUserID,
  }),
);

虽然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;
    }, []);
}

jsbin示例

即使提供的列表中的某个项不是对象或不包含该字段,这也会起作用。

如果项不是对象或不包含字段,甚至可以通过协商默认值来使其更加灵活。

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;
    }, []);
}

jsbin示例

这与map相同,因为返回的数组的长度与提供的数组相同。(在这种情况下,地图比缩减略便宜):

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;
    }, []);
}

jsbin示例

还有一个最灵活的解决方案,它可以让你通过提供一个替代价值在两种行为之间切换。

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;
    }, []);
}

jsbin示例

正如上面的示例(希望)揭示了这一工作方式,让我们通过使用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 : []));
    }, []);
}

jsbin示例

在ES6中,您可以执行以下操作:

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

上述答案适用于单个属性,但当从数组中选择多个财产时,请使用以下选项

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)