logo
Published on

如何在 JavaScript 中检查数组是否包含某个值?

Authors
  • Name
    Twitter

在 JavaScript 中,我们经常需要检查数组是否包含某个值。传统的做法是使用 indexOflastIndexOf 方法,但是这些方法在处理大型数组时性能并不理想。本文将介绍一种双向查找的方法,能够有效提高查找速度。

背景

虽然 includes 方法提供了一个便捷的接口,但是目前支持度还较低。因此,我们需要寻找一种替代 indexOflastIndexOf 的方法。

在众多优化方案中,@Damir Zekic 提出的 contains 函数表现最佳。然而,该方案的基准测试数据较为陈旧,可能不再适用。因此,我们提出了一种双向查找的方法,可以显著提升查找速度。

双向查找方法

通过在遍历数组时同时从两端进行比较,可以减少遍历次数,从而提高性能。下面是实现该方法的代码:

function bidirectionalIndexOf(a, b, c, d, e) {
  for (c = a.length, d = c * 1; c--; ) {
    if (a[c] == b) return c // 或者使用 a[c]===b
    if (a[(e = d - 1 - c)] == b) return e // 或者使用 a[e=d-1-c]===b
  }
  return -1
}

// 用法示例
bidirectionalIndexOf(array, 'value')

该方法在实际应用中比传统方法快约两倍,特别适用于大型数组的查找操作。

性能测试

为了验证该方法的性能,我创建了一个包含 10 万个元素的数组,并进行了三次查找操作:在数组的开头、中间和结尾。性能测试结果可以访问以下链接:

性能测试结果

数组原型变体

为了便于调用,我们还可以将该方法添加到数组的原型上:

Object.defineProperty(Array.prototype, 'bidirectionalIndexOf', {
  value: function (b, c, d, e) {
    for (c = this.length, d = c * 1; c--; ) {
      if (this[c] == b) return c // 或者使用 this[c]===b
      if (this[(e = d - 1 - c)] == b) return e // 或者使用 this[e=d-1-c]===b
    }
    return -1
  },
  writable: false,
  enumerable: false,
})

// 用法示例
array.bidirectionalIndexOf('value')

我们还可以对该方法进行简单修改,使其返回 truefalse,如需返回匹配的对象、字符串或其他类型的数据,也可以进行对应调整。

另一个实现(while 循环)

另外,我们还可以使用 while 循环实现相同的功能:

function bidirectionalIndexOf(a, b, c, d) {
  c = a.length
  d = c - 1
  while (c--) {
    if (b === a[c]) return c
    if (b === a[d - c]) return d - c
  }
  return c
}

// 用法示例
bidirectionalIndexOf(array, 'value')

为什么这种方法有效?

通过简单计算得到数组中的对称索引,比逐一遍历数组快两倍。

即使是更复杂的示例,每次迭代进行三次检查,这种方法依然表现优异。更详细的性能测试可以访问以下链接:

复杂性能测试