如何确定Javascript数组是否包含具有等于给定值的属性的对象?

Dav*_*zzi 538 javascript arrays

我有一个类似的数组

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];
Run Code Online (Sandbox Code Playgroud)

如何检查此数组以查看Magenic是否存在?我不想循环,除非我必须.我正在处理可能有几千条记录.

更新

由于这是一个受欢迎的帖子,我想我会分享一些新发现的东西.似乎@CAFxX已经分享了这个!我应该经常阅读这些内容.我遇到了https://benfrain.com/understanding-native-javascript-array-methods/.

vendors.filter(function(vendor){ return vendor.Name === "Magenic" });
Run Code Online (Sandbox Code Playgroud)

使用ECMAScript 2015,使用新的箭头功能更简单:

vendors.filter(vendor => (vendor.Name === "Magenic"));
Run Code Online (Sandbox Code Playgroud)

CAF*_*FxX 769

没有必要重新发明 循环,至少没有明确(使用箭头函数,仅现代浏览器):

if (vendors.filter(e => e.Name === 'Magenic').length > 0) {
  /* vendors contains the element we're looking for */
}
Run Code Online (Sandbox Code Playgroud)

或者,更好的是:

if (vendors.some(e => e.Name === 'Magenic')) {
  /* vendors contains the element we're looking for */
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果你需要与糟糕的浏览器兼容,那么你最好的选择是:

if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
  /* vendors contains the element we're looking for */
}
Run Code Online (Sandbox Code Playgroud)

  • 我想,这取决于你对糟糕的定义.该语法是javascript 1.8的一部分. (23认同)
  • @7hibault 因为一旦找到具有 `name === "Magenic"` 的对象,`some` 就会短路。使用`filter`,它将检查每个项目直到数组的末尾并创建一个与条件匹配的新数组项目,然后检查`length` (8认同)
  • 您在第一个和第二个示例中使用的[表达式闭包](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Expression_closures)具有**非标准,不要使用来自Mozilla的!**警告(请参阅该链接).他们只在Firefox中工作,现在已被弃用,将被删除,转而使用[arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). (7认同)
  • 很多关于“.some”的评论。现在是 2019 年,使用 `.some` 并使用 Polyfills 来支持糟糕的浏览器并继续你的生活...polyfill.io/v3/url-builder。我唯一能看到的是,如果你不能支持箭头函数,那么它就像我提到的 Polyfill 一样简单:`arr.some(function(i) { return i.Name === "Magenic" })` (7认同)
  • @CAFxX 找到后如何获取索引?这是否有可能,或者循环可以更好地获取索引? (5认同)
  • @Echtniet如果您需要索引,那么vendors.findIndex将为您提供第一个匹配元素的索引。相反,如果您需要该值,则 sellers.find 将提供第一个匹配元素,而 sellers.filter 将提供所有匹配元素。您可能需要参考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array (5认同)
  • @Rocket你为什么编辑我的答案?没有花括号的语法是[完全有效的javascript](https://developer.mozilla.org/en/New_in_JavaScript_1.8#Expression_closures_%28Merge_into_own_page.2Fsection%29). (4认同)
  • "lambda"语法仍然无法在Chrome 16中运行(这不是一个糟糕的浏览器). (4认同)
  • 为什么“some”*更好*? (2认同)

Ale*_*pin 232

2018编辑:这个答案来自2011年,之前浏览器广泛支持阵列过滤方法和箭头功能.看看CAFxX的答案.

在没有循环的情况下,没有"神奇"的方法来检查数组中的某些东西.即使你使用某个函数,函数本身也会使用循环.您可以做的就是在找到所需内容时尽快摆脱循环,以最大限度地缩短计算时间.

var found = false;
for(var i = 0; i < vendors.length; i++) {
    if (vendors[i].Name == 'Magenic') {
        found = true;
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 没问题.请记住,[Keith的解决方案](http://stackoverflow.com/questions/8217419/how-to-determine-if-json-array-contains-object/8217459#8217459)也非常可行,可以避免循环. (4认同)
  • 这些选项现在似乎有效:vendors.forEach,vendors.filter,vendors.reduce (4认同)
  • @LastBreath 如果 `'Magenic'` 在对象的其他地方,很容易导致误报 (4认同)
  • 如果你需要知道的是"某物"是否存在,你不需要一个标志,你可以用数组的大小来检查扫描索引的值.为此,索引var需要在for语句之前声明. (2认同)

box*_*ain 71

无需循环.想到的三种方法:

Array.prototype.some()

这是你问题的最准确答案,即"检查是否存在某种东西",这意味着一个bool结果.如果存在任何"Magenic"对象,则为true,否则为false:

let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )
Run Code Online (Sandbox Code Playgroud)

Array.prototype.filter()

这将返回所有"Magenic"对象的数组,即使只有一个(将返回单元素数组):

let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )
Run Code Online (Sandbox Code Playgroud)

如果你试图将它强制转换为布尔值,它将无法工作,因为一个空数组(没有'Magenic'对象)仍然是真的.所以只需magenicVendors.length在条件中使用即可.

Array.prototype.find()

这将返回第一个'Magenic'对象(或者undefined如果没有):

let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );
Run Code Online (Sandbox Code Playgroud)

这强制到布尔值(任何对象都是真实的,undefined是假的).


注意:由于属性名称的奇怪外壳,我使用供应商["Name"]而不是vendor.Name.

注2:检查名称时没有理由使用松散等式(==)而不是严格相等(===).

  • 有必要指出,在引擎盖下,这些都是循环的.这些也比简单地用于循环和执行操作的计算速度慢. (2认同)

Tea*_*der 41

接受的答案仍然有效,但现在我们有一个ECMAScript 6本机方法[Array.find][1]来实现相同的效果.

引用MDN:

find()方法返回数组中第一个满足提供的测试函数的元素的值.否则返回undefined.

var arr = []; 
var item = {
  id: '21',
  step: 'step2',
  label: 'Banana',
  price: '19$'
};

arr.push(item);
/* note : data is the actual object that matched search criteria 
  or undefined if nothing matched */
var data = arr.find( function( ele ) { 
    return ele.id === '21';
} );

if( data ) {
 console.log( 'found' );
 console.log(data); // This is entire object i.e. `item` not boolean
}
Run Code Online (Sandbox Code Playgroud)

请参阅我的jsfiddle链接有一个由mozilla提供的 IE的polyfill

  • 如果你只是返回ele.id =='2',可以更短,但是对于一个好的ES6解决方案来说+1. (2认同)

Kei*_*amo 21

除非你想像这样重组它:

vendors = {
    Magenic: {
      Name: 'Magenic',
      ID: 'ABC'
     },
    Microsoft: {
      Name: 'Microsoft',
      ID: 'DEF'
    } and so on... 
};
Run Code Online (Sandbox Code Playgroud)

你能做到的 if(vendors.Magnetic)

你将不得不循环

  • 如果他仍然想要维护对象结构以便在其他地方使用它 (2认同)

Mir*_*eka 21

这是我做的方式

const found = vendors.some(item => item.Name === 'Magenic');
Run Code Online (Sandbox Code Playgroud)

array.some()方法检查数组中是否至少有一个值与条件匹配并返回一个布尔值.从这里你可以去:

if (found) {
// do something
} else {
// do something else
}
Run Code Online (Sandbox Code Playgroud)


小智 20

根据ECMAScript 6规范,您可以使用findIndex.

const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');

magenicIndex将保留0(或者是数组中的索引)或者-1如果找不到它.


Aki*_*oni 20

可能为时已晚,但 javascript 数组有两个方法someevery返回布尔值的方法,可以帮助您实现这一目标。

我认为some最适合您打算实现的目标。

vendors.some( vendor => vendor['Name'] !== 'Magenic' )
Run Code Online (Sandbox Code Playgroud)

有些验证数组中的任何对象满足给定条件。

vendors.every( vendor => vendor['Name'] !== 'Magenic' )
Run Code Online (Sandbox Code Playgroud)

Every 验证数组中的所有对象都满足给定条件。


Jay*_*kra 15

由于OP已经询问密钥是否存在.

一个更优雅的解决方案,将使用ES6 reduce函数返回布尔值

const magenicVendorExists =  vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);
Run Code Online (Sandbox Code Playgroud)

注意: reduce的初始参数是a false,如果数组有键,它将返回true.

希望它有助于更​​好,更清晰的代码实现

  • 另请检查 Mirza Leka 的解决方案。一个更优雅的解决方案。 (2认同)

jAn*_*ndy 13

你不能没有真正地看着对象.

你可能应该改变你的结构,比如

vendors = {
    Magenic:   'ABC',
    Microsoft: 'DEF'
};
Run Code Online (Sandbox Code Playgroud)

然后你可以像查询哈希一样使用它.

vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
Run Code Online (Sandbox Code Playgroud)


Wil*_*een 9

测试数组元素:

JS 提供了数组函数,可以让你相对容易地实现这一点。它们如下:

  1. Array.prototype.filter: 接受一个作为测试的回调函数,然后使用 is callback 迭代数组并根据此回调进行过滤。返回一个新的过滤数组。
  2. Array.prototype.some:接受一个作为测试的回调函数,然后使用 is 回调迭代数组,如果任何元素通过测试, 则返回布尔值 true。否则返回 false

最好通过一个例子来解释细节:

例子:

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

// filter returns a new array, we instantly check if the length 
// is longer than zero of this newly created array
if (vendors.filter(company => company.Name === 'Magenic').length ) {
  console.log('I contain Magenic');
}

// some would be a better option then filter since it directly returns a boolean
if (vendors.some(company => company.Name === 'Magenic')) {
  console.log('I also contain Magenic');
}
Run Code Online (Sandbox Code Playgroud)

浏览器支持:

这 2 个函数是ES6函数,并非所有浏览器都支持它们。为了克服这个问题,您可以使用 polyfill。这是Array.prototype.some(来自 MDN)的 polyfill :

if (!Array.prototype.some) {
  Array.prototype.some = function(fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}
Run Code Online (Sandbox Code Playgroud)


小智 9

const check = vendors.find((item)=>item.Name==='Magenic')

console.log(check)
Run Code Online (Sandbox Code Playgroud)

试试这个代码。

如果项目或元素存在,则输出将显示该元素。如果它不存在,则输出将为“未定义”。


nhC*_*der 9

迄今为止最简单的方法:

if (vendors.findIndex(item => item.Name == "Magenic") == -1) {
  //not found item
} else {
  //found item 
}
Run Code Online (Sandbox Code Playgroud)


rot*_*est 7

我解决这个问题的方法是使用 ES6 并创建一个函数来为我们进行检查。此函数的好处是,它可以在整个项目中重复使用,以检查给定的任何对象数组keyvalue要检查的对象。

说得够多了,让我们看看代码

大批

const ceos = [
  {
    name: "Jeff Bezos",
    company: "Amazon"
  }, 
  {
    name: "Mark Zuckerberg",
    company: "Facebook"
  }, 
  {
    name: "Tim Cook",
    company: "Apple"
  }
];
Run Code Online (Sandbox Code Playgroud)

功能

const arrayIncludesInObj = (arr, key, valueToCheck) => {
  return arr.some(value => value[key] === valueToCheck);
}
Run Code Online (Sandbox Code Playgroud)

通话/使用

const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true

const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false
Run Code Online (Sandbox Code Playgroud)


yur*_*rin 6

函数mapfilterfind和类似函数比简单循环慢。对我来说,它们的可读性也比简单循环差,并且更难调试。使用它们看起来像是一种非理性的仪式。

最好有这样的东西:

 arrayHelper = {
     arrayContainsObject: function (array, object, key){
         for (let i = 0; i < array.length; i++){
            if (object[key] === array[i][key]){
                 return true;
            }
         }
         return false;
     }
     
   };
Run Code Online (Sandbox Code Playgroud)

并像这样使用给定的 OP 示例:

    vendors = [{
    Name: 'Magenic',
    ID: 'ABC'
     },
     {
    Name: 'Microsoft',
    ID: 'DEF'
     } 
  ];

let abcObject = {ID: 'ABC', Name: 'Magenic'};

let isContainObject = arrayHelper.arrayContainsObject(vendors, abcObject, 'ID');
Run Code Online (Sandbox Code Playgroud)

  • map、filter、find 更具可读性,代码也更小、编写速度更快 (3认同)

Tom*_*lak 5

您必须循环,无法解决。

function seekVendor(vendors, name) {
  for (var i=0, l=vendors.length; i<l; i++) {
    if (typeof vendors[i] == "object" && vendors[i].Name === name) {
      return vendors[i];
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,您可以使用像linq.js这样的库来使此过程更令人愉悦:

Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();
Run Code Online (Sandbox Code Playgroud)

(有关演示,请参见jsFiddle

我怀疑linq.js会比直接循环更快,但是当事情变得更复杂时,它肯定会更灵活。


Eth*_*han 5

如果您使用jQuery,您可以利用 grep 创建包含所有匹配对象的数组:

var results = $.grep(vendors, function (e) {
    return e.Name == "Magenic";
});
Run Code Online (Sandbox Code Playgroud)

然后使用结果数组:

for (var i=0, l=results.length; i<l; i++) {
    console.log(results[i].ID);
}
Run Code Online (Sandbox Code Playgroud)


Sid*_*hra 5

如果我错了请纠正我..我可以使用这样的forEach方法,

var found=false;
vendors.forEach(function(item){
   if(item.name === "name"){
       found=true;

   }
});
Run Code Online (Sandbox Code Playgroud)

现在我已经习惯了,因为它简单且不言自明。谢谢你。

  • 注意:此处不使用 return (2认同)

JBa*_*lin 5

2021 解决方案

Lodash .some( docs ) 是一个干净的解决方案,如果您使用_matchesProperty( docs ) 速记:

_.some(VENDORS, ['Name', 'Magenic'])
Run Code Online (Sandbox Code Playgroud)

解释

这将遍历VENDORSArray 以查找Name具有 String 值的键的元素 Object 'Magenic'。一旦找到这个元素,它就会返回true并停止迭代。如果在查看整个 Array 后没有找到该元素,则返回false

代码片段

const VENDORS = [{ Name: 'Magenic', ID: 'ABC' }, { Name: 'Microsoft', ID: 'DEF' }];

console.log(_.some(VENDORS, ['Name', 'Magenic'])); // true
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"></script>
Run Code Online (Sandbox Code Playgroud)