javascript中的IndexOf方法比遍历数组更有效吗?

Posted

技术标签:

【中文标题】javascript中的IndexOf方法比遍历数组更有效吗?【英文标题】:Is the IndexOf method in javascript more efficient than iterating through an array? 【发布时间】:2016-03-24 00:35:21 【问题描述】:

我有一个 JSON 对象数组,我想找到具有特定属性的对象。我知道这可能看起来像一个重复的问题,但请继续,因为我认为它与之前的问题略有不同。

与我一起工作的一个人建议使用 IndexOf,这让我开始思考。有没有类似于 mongo 中的 $elemMatch 功能的东西?是否有一些命令基本上用伪代码表示“从这个数组中获取具有此属性的对象”?随着迭代,我觉得伪代码说“看看这个数组中的第一个对象。如果这个对象有这个属性,给我这个对象。如果没有,看看这个数组中的第二个对象...... "

我了解如何使用我朋友建议的 IndexOf,但我越想越开始认为 IndexOf 方法可能代码行数更少,但它最终是否必须遍历数组来找到我需要的索引?所以如果我想用这个属性对对象做一些事情,并且我使用 IndexOf 方法来获取索引,我会像 myArray[indexFromIndexOfMethod] 这样引用对象,然后相应地修改它,对吗?因此,如果 javascript 正在遍历数组本身以执行 IndexOf 方法,为什么我不编写自己的迭代并保存一个步骤?现在,如果 IndexOf 方法使用一种比仅迭代和检查每个元素更有效的方法来定位数组元素,那么使用它对我来说是有意义的。否则,如果您可以通过简单的迭代获得相同的结果,那么使用 IndexOf 方法没有意义。

【问题讨论】:

我需要更好地解释为什么使用indexOf“没有意义”,因为您可以编写自己的迭代并复制已经编写的代码。 不确定不使用indexOf 会如何为您节省任何费用。有了它,您不必编写循环,它会为您完成循环。 但是我想使用该对象执行的操作可能发生在该对象位于数组中的那一刻。因此,如果我编写自己的迭代,我可以将所有这些内容添加到函数中。如果我使用 IndexOf,javascript 将尽一切努力找到我正在寻找的元素的索引,然后当它完成时,我可以使用生成的索引来获取该对象。因此,如果 IndexOf 不比迭代更有效,我可以将这两个步骤合二为一。 通过索引访问数组元素是如此之快,你永远不会注意到差异 jsperf 稍微支持indexOf。但如前所述,这仅在我们与完全相同的对象进行比较时才有效。如果您要基于标识属性搜索不同但相同的对象,indexOf 将失败,但所有其他情况都可以。 【参考方案1】:

Array.prototype.indexOf 也只是遍历数组并返回具有匹配值的第一个索引。你可以用循环做同样的事情。它可能或可能不会比for 循环稍微快一点,因为indexOf 可以在本机代码中实现并进行不同于for 循环的优化,但没有根本区别。

如果您经常需要尽快访问特定值,则值得在对象中按该值对它们进行索引。这意味着,如果您想经常通过其属性.foo 查找特定对象,请执行以下操作:

var byFoo = 
for (var i = 0; i < myArray.length; i++) 
    byFoo[myArray[i].foo] = myArray[i];

然后,您可以使用byFoo['baz'] 即时访问。

当然,这有可能在多个副本中维护这些索引的额外开销,但它会使数组访问速度提高许多数量级。你需要权衡利弊。

【讨论】:

谢谢你的好回答。我可以告诉你,你完全理解我在问什么,我觉得这里的其他人都没有。有时,最好将一个问题阅读几遍以全面理解它,而不是快速浏览它并试图得到第一个答案。 好吧,如果问题更紧凑并包含代码示例,它有所帮助... :-P @ChristopherFlint 我想每个人都理解你的问题。我们不明白的是,您通过在循环中编写代码、在找到相关值后退出该循环等来复制indexOf 功能,从而实现“节省”。【参考方案2】:

如果它们是真实对象,indexOf 将不会对对象起作用,因为即使两个对象具有相同的属性值,它们也会彼此不同,因此您不能使用真实对象作为 indexOf 的输入。

只有当 JSON 仍然是未解析的字符串时它才会起作用,那么它将是最有效的方法。

因此,如果我必须直接引用对象,我倾向于使用的解决方案是创建包含每个对象索引的引用,或者只使用对象本身而不是数组来存储数据对象,并使用唯一标识符,如数据对象的 id,作为键。

// This will fail:
var data = [
    
        'id' : 1,
        'value' : 'myDataForObj1'
    ,
    
        'id' : 2,
        'value' : 'myDataForObj2'
    
];

data.indexOf(
    'id' : 2,
    'value' : 'myDataForObj2'   
); // return -1, as in, not found.


// This will work:
var data = [
    '"id":1,"value":"myDataForObj1"',
    '"id":2,"value":"myDataForObj2"'
];

data.indexOf('"id":2,"value":"myDataForObj2"'); // return 1, as in the second element in the array.

// This is what I usually use:
var data = 
    'id1' :     
        'id' : 1,
        'value' : 'myDataForObj1'
    ,
    'id2' : 
        'id' : 2,
        'value' : 'myDataForObj2'
    
;

data['id2'].value = 'newValue';

您必须采取某种方式来引用您想要直接访问的所有内容,因此如果您希望能够在任何对象中找到任何值,对于具有大量属性的对象来说,循环可能会更容易实现.

因此,我养成了总是将一些“id”与我必须操作的数据相关联的习惯。例如,最终用户单击表中的一行来编辑它。我将确保该行具有引用数据在模型中的 id 的数据属性,该数据与它在后端的 id 相同。在大多数情况下,这种设计消除了对数据存储进行迭代的需要。

【讨论】:

谢谢你,我很欣赏这个答案,如果我可以选择两个最佳答案,我会选择你的。不幸的是,下一个人对我的具体问题的回答要好一些。

以上是关于javascript中的IndexOf方法比遍历数组更有效吗?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript中的indexOf使用方法

javaScript中的indexOf使用方法

Javascript中的数组去重-indexof方法

JavaScript——数组的indexOf()方法在IE8中的兼容性问题

Javascript数组去重的几种方法

Javascript基础学习20问