对象数组中的 indexOf 方法?

IT技术 javascript
2021-01-23 14:27:56

获取包含对象的数组索引的最佳方法是什么?

想象一下这个场景:

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

现在我想要属性是indexOf的对象,在这个例子中,将是.hello'stevie'1

我是 JavaScript 的新手,我不知道是否有一个简单的方法,或者我是否应该构建自己的函数来做到这一点。

6个回答

我认为您可以使用map函数在一行中解决它

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
从技术上讲,缩小的 js 文件也是一行;D
2021-03-15 14:27:56
嗯...不是值得注意的是 Array.prototype.map() 创建一个包含映射项的全新数组吗?所以,如果你有一个包含 1000 个元素的数组,你是否先创建了另一个包含 1000 个元素的数组,然后搜索它?我认为看看这个方法与简单的 for 循环的性能是值得的。特别是当您在资源有限的移动平台上运行时。
2021-03-19 14:27:56
老实说,这应该是公认的答案。现在大多数浏览器都支持Array.prototype.map()
2021-03-22 14:27:56
@Doug 尽管您关于性能的观点确实是正确的,但在他们的头脑中,对于几乎根据定义 IO/网络绑定的应用程序,在他们分析瓶颈之前,谁会用七行代码替换一行代码?
2021-03-29 14:27:56
IE8 不支持它,但是,如果这不是问题,这是最好的解决方案。
2021-04-08 14:27:56

Array.prototype.findIndex在除 IE(非边缘)之外的所有浏览器中都受支持。但是提供polyfill很好。

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");

带地图的解决方案没问题。但是您每次搜索都会遍历整个数组。这只是findIndex的最坏情况,一旦找到匹配,它就会停止迭代。


没有真正简洁的方法 (当开发人员不得不担心 IE8 时),但这里有一个常见的解决方案:

var searchTerm = "stevie",
    index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
    if (myArray[i].hello === searchTerm) {
        index = i;
        break;
    }
}

或作为一个函数:

function arrayObjectIndexOf(myArray, searchTerm, property) {
    for(var i = 0, len = myArray.length; i < len; i++) {
        if (myArray[i][property] === searchTerm) return i;
    }
    return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1

只是一些注意事项:

  1. 不要在数组上使用 for...in 循环
  2. 一旦你找到你的“针”,一定要跳出循环或返回函数
  3. 小心对象相等

例如,

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found
该函数的 searchterm 比较错误,因为它应该是 searchTerm :)
2021-03-11 14:27:56
@SteveBennett 这是一个性能优化的版本;数组的长度只需确定一次(当 for 循环的变量被初始化时)。在您的情况下,每次迭代都会重新检查长度。另请参阅stackoverflow.com/questions/5349425/...stackoverflow.com/questions/8452317/... 但是,如果性能不是很高的优先级,则它并不重要。
2021-03-25 14:27:56
发生了多次
2021-03-27 14:27:56
很好的答案,但我做了一些性能基准测试(参见jsperf.com/find-index-of-object-in-array-by-contents),发现这里提到的基于函数的答案似乎是性能第二高的答案。正如我的回答中提到的那样,唯一更高效的最终是将其放入原型中,而不仅仅是一个函数
2021-03-31 14:27:56

在 ES2015 中,这很容易:

myArray.map(x => x.hello).indexOf('stevie')

或者,对于较大的数组可能具有更好的性能:

myArray.findIndex(x => x.hello === 'stevie')
@Uniphonic - 2021 年 findIndex,如果所有浏览器都支持,OperaMini 和 IE 除外 - caniuse.com/array-find-index
2021-03-16 14:27:56
正如我在回答中提到的那样,我很惊讶这些方法都没有原型 for 循环那么高效。尽管对 findIndex 方法的浏览器支持有点差,但它似乎会做同样的事情,但最终性能仍然较低?有关基准测试,请参阅我的答案中的链接。
2021-03-18 14:27:56
很高兴知道,如果性能对手头的任务很重要。根据我的经验,它很少是 ymmv。
2021-03-21 14:27:56
使用 ES6 的好方法
2021-04-08 14:27:56
var idx = myArray.reduce( function( cur, val, index ){

    if( val.hello === "stevie" && cur === -1 ) {
        return index;
    }
    return cur;

}, -1 );

我喜欢 Pablo 的回答,但 Array#indexOf 和 A​​rray#map 不适用于所有浏览器。如果可用,下划线将使用本机代码,但也有回退。此外,它还具有 pluck 方法,可以完全完成 Pablo 的匿名映射方法所做的工作。

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
chain 这里是多余的。 _.pluck(myArray, 'hello').indexOf('stevie')
2021-03-16 14:27:56
我真的很喜欢 Underscore,你的回答也很聪明,但恕我直言,Pablo 的回答是最干净的。
2021-03-22 14:27:56
哇,我从没想过要像那样使用链接。我真的很喜欢它如何使搜索流畅。
2021-03-23 14:27:56
Array.prototype.map() 支持 IE9+,你可以为 IE8、7、6 使用 Polyfill: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-04-03 14:27:56
您可以使用 polyfill 。. . 或者你可以只使用下划线或 lodash,它们基本上是附加了一大堆其他好东西的 polyfill带下划线的反对意见是什么?尺寸?
2021-04-09 14:27:56