通过属性值获取数组对象中的JavaScript对象

1295

假设我有一个包含四个对象的数组:

var jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

有没有一种方式可以通过属性 b 的值来获取第三个对象 ({a: 5, b: 6}),例如不使用 for...in 循环?


1
是的,只要b的值在数组中所有对象中是唯一的(在此示例中是这样),就是可能的。 - Will C.
@undefined 我很确定OP想要在数组中搜索对象b = 6 - Madbreaks
1
我喜欢简短、兼容ES6之前的浏览器的代码... jsObjects.find(function(x) {if(x.b == 6) return x})你可以同时获取属性a...jsObjects.find(function(x) {if(x.b == 6) return x}).a - Mark Seagoe
17个回答

1799

筛选对象数组中属性匹配值的元素,返回一个新的数组:

var result = jsObjects.filter(obj => {
  return obj.b === 6
})

请查看MDN文档中有关Array.prototype.filter()的内容

const jsObjects = [
  {a: 1, b: 2}, 
  {a: 3, b: 4}, 
  {a: 5, b: 6}, 
  {a: 7, b: 8}
]

let result = jsObjects.filter(obj => {
  return obj.b === 6
})

console.log(result)

查找数组中第一个元素/对象的值,否则返回 undefined

var result = jsObjects.find(obj => {
  return obj.b === 6
})

请查看MDN文档中有关Array.prototype.find()的内容

const jsObjects = [
  {a: 1, b: 2}, 
  {a: 3, b: 4}, 
  {a: 5, b: 6}, 
  {a: 7, b: 8}
]

let result = jsObjects.find(obj => {
  return obj.b === 6
})

console.log(result)


176
这将返回一个数组。 - nickf
45
@nickf。我认为应该这样做,如果有更多具有相同属性的对象怎么办?否则:在这种情况下result[0]将是第一个(唯一的)对象。 - elclanrs
34
让它仅返回第一个很容易。在末尾添加"[0]"。 #javaScriptIsAwesome! var result = jsObjects.filter(function(obj) { return obj.b == 6; })[0]; - Rap
37
问题是“获取JavaScript对象”,而不是“对象数组”。 - Michał Perłakowski
29
@Gothdo是正确的。要获取对象,我们可以使用Array.find方法: var result = jsObjects.find(function(obj) { return obj.b === 6; }); - kolodi
显示剩余15条评论

482
jsObjects.find(x => x.b === 6)

来自 MDN:

find() 方法会在数组中查找一个满足测试函数的元素并返回其值。否则返回 undefined


顺便提一下:像 find() 和箭头函数这样的方法不被旧版浏览器(如 IE)支持,所以如果你需要支持这些浏览器,你应该使用 Babel 进行转译。


7
请注意,这在IE浏览器中不受支持。 - 29er
57
是的,我写过“像 find() 和箭头函数这样的方法不被所有浏览器支持”。 - Michał Perłakowski
4
如果您想修改原始数组中的对象,最佳选择是使用这种方法。filter()会返回一个对象的副本,而不是原始对象,因此对其进行更改不会反映在原始数组中。 - ahaurat
6
原文:@thdoan The OP asked for "the object", not "an array of matching objects". elclanrs's answer is wrong.翻译:OP要求“对象”,而不是“匹配对象的数组”。elclanrs的回答是错误的。 - Michał Perłakowski
2
因为IE不支持,所以我点了赞。是时候向前迈进了,而我正在使用它来实现这个目标。 - RayLoveless
显示剩余2条评论

199

我不知道你为什么反对for循环(我想你指的是for loop,而不是特定的for..in),它们快速且容易阅读。无论如何,这里有几个选项。

For循环:

function getByValue(arr, value) {

  for (var i=0, iLen=arr.length; i<iLen; i++) {

    if (arr[i].b == value) return arr[i];
  }
}

.筛选器

function getByValue2(arr, value) {

  var result  = arr.filter(function(o){return o.b == value;} );

  return result? result[0] : null; // or undefined

}

.forEach

function getByValue3(arr, value) {

  var result = [];

  arr.forEach(function(o){if (o.b == value) result.push(o);} );

  return result? result[0] : null; // or undefined

}
如果你确实想要使用 for..in 并且想要查找任何属性值为 6 的对象,那么除非传递要检查的名称,否则必须使用 for..in。 示例
function getByValue4(arr, value) {
  var o;

  for (var i=0, iLen=arr.length; i<iLen; i++) {
    o = arr[i];

    for (var p in o) {
      if (o.hasOwnProperty(p) && o[p] == value) {
        return o;
      }
    }
  }
}

19
哪一个是最快的? - SalmanShariati
6
根据性能测试结果(https://jsperf.com/extract-props/1),for循环是迄今为止最快的方法。 - Adriano P
3
使用ES6及以上版本的语法,可以使用以下代码进行循环遍历数组中的元素:for(let value of arr) - pungggi
2
@RobG,将arr.length存储在 iLen 而不是直接在 for 循环条件中使用 i<arr.length,是否有特定的原因? - Vikas Prasad
1
@VikasPrasad——只是一个小的性能增强,可能现在没有帮助,但在早期确实有用。 - RobG
显示剩余2条评论

77

实现要求的方法:

  1. 使用 Array.find() 方法

const jsObject = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

const filteredResult = jsObject.find((e) => e.b == 6);

console.log(filteredResult);

  1. 使用 Array.filter() 方法

const jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

const filterObj = jsObjects.filter((e) => e.b == 6);

console.log(filterObj[0]);

  1. 使用for...in循环:

const jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

for (const i in jsObjects) {
  if (jsObjects[i].b == 6) {
    console.log(jsObjects[i]);
  }
}


33

好的,有几种方法可以做到这一点,但让我们从最简单和最新的方法开始,这个函数被称为find()

只要在使用find时小心,因为即使IE11也不支持它,所以它需要被转译...

所以你有了如你所说的这个对象:

var jsObjects = [
   {a: 1, b: 2}, 
   {a: 3, b: 4}, 
   {a: 5, b: 6}, 
   {a: 7, b: 8}
];

你可以编写一个函数并像这样获取它:

function filterValue(obj, key, value) {
  return obj.find(function(v){ return v[key] === value});
}

并像这样使用函数:

filterValue(jsObjects, "b", 6); //{a: 5, b: 6}

在ES6中还有更短的版本:

const filterValue = (obj, key, value)=> obj.find(v => v[key] === value);

这个方法仅返回第一个匹配的值,如果想获得更好的结果和浏览器支持,可以使用 filter

const filterValue = (obj, key, value)=> obj.filter(v => v[key] === value);

我们将会返回[{a: 5, b: 6}]的数组...

这个方法将会返回一个数组...

你同样可以使用for循环,创建如下函数:

function filteredArray(arr, key, value) {
  const newArray = [];
  for(i=0, l=arr.length; i<l; i++) {
    if(arr[i][key] === value) {
      newArray.push(arr[i]);
    }
  }
 return newArray;
}

然后像这样调用它:

filteredArray(jsObjects, "b", 6); //[{a: 5, b: 6}]

2
感谢@Alireza。 非常完整的答案。至于.filter部分: <该方法将返回一个数组而不是... 这不是最优雅的解决方案,但考虑在末尾添加[0],以进行快速修复。 const filterValue = (obj, key, value)=> obj.filter(v => v[key] === value)[0]; - user3658510

30

请参阅文档 Array.prototype.find()

示例:

var inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];

function findCherries(fruit) { 
    return fruit.name === 'cherries';
}

console.log(inventory.find(findCherries)); 
// { name: 'cherries', quantity: 5 }

3
不清楚你调用的 'find()' 方法是如何工作的。另外,Internet Explorer 不支持 Object.values() 方法。 - ryanwebjackson
1
看起来链接是错误的。作者可能想要这个链接:Array.prototype.find() - user3658510
1
如果找不到任何内容,这会返回什么?undefined? - Oliver Dixon
1
@OliverDixon 是的。 - asrulsibaoel

23

使用underscore.js:

var foundObject = _.findWhere(jsObjects, {b: 6});

已弃用,请使用_.find代替:https://dev59.com/YWYr5IYBdhLWcg3wFGZS#40958199 - genericUser

21

看起来在ECMAScript 6提案中有Array方法find()findIndex()。MDN还提供了填充物(polyfills),您可以包含它们以在所有浏览器中获得这些功能。

find():

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

findIndex():

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].findIndex(isPrime) ); // -1, not found
console.log( [4, 6, 7, 12].findIndex(isPrime) ); // 2

19

如果你想要一个单一的结果而不是一个数组,我建议使用reduce方法。

以下是使用普通的JavaScript编写的解决方案,如果存在匹配的对象,则返回该对象;否则返回null。

var result = arr.reduce(function(prev, curr) { return (curr.b === 6) ? curr : prev; }, null);

18

如果我理解正确,你想要在数组中找到其 b 属性为 6 的对象?

var found;
jsObjects.some(function (obj) {
  if (obj.b === 6) {
    found = obj;
    return true;
  }
});

或者,如果您使用下划线:

var found = _.select(jsObjects, function (obj) {
  return obj.b === 6;
});

3
some只返回true或false,不会返回匹配的对象。 - RobG
6
@RobG,是的,我很清楚。注意我没有给它分配值吗? :) 它只是在这里用作一种短路循环的方法。 - nickf
过于复杂了。.some() 的作用是确定数组中是否有元素通过测试。在这种情况下,最好使用 .forEach(),因为您已经决定将结果分配给一个变量。 - Michał Perłakowski
@Gothdo 为什么在已经得到结果的情况下还要继续循环数组呢?在 .some 中的 return true 实际上就像是 for 循环中的 break - nickf

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