如何避免使用 ES9 的 Array.prototype.includes() 出现的错误

阅读时长 6 分钟读完

ES9(ECMAScript 2018)引入了一个方便的方法 Array.includes(),它可以检测一个数组是否包含某个元素。然而,在进行元素比较时,它会使用 JavaScript 的内置 SameValueZero 算法,这可能会导致错误。

在本文中,我们将介绍这个问题的背景和原因,并提供几种避免这个问题的方法。

问题的背景

Array.includes() 方法将使用 SameValueZero 算法去比较数组元素和待查找元素。简单说,如果两个值完全相同,则返回 true。但是,这种比较可能不是我们想要的。

考虑如下示例,我们将两个对象添加到数组中,它们具有相同的内容但是却是不同的实例:

这个结果可能出乎意料。尽管数组中包含 id 属性值为 1 的对象,但是 Array.includes() 返回了 false。这是因为 obj 对象和数组中的对象在 JavaScript 中是不同的实例。

这个问题可能在以下情况下产生:

  • 在使用流行的 Redux 状态管理库时,通常需要在 Redux 中比较对象。如果你使用了 Array.includes(),可能会遇到这个问题。
  • 当你比较两个由不同组件传递到 React 组件时的对象时,也可能会遇到这个问题。

解决方案

现在我们已经了解了问题所在,那么如何避免这个问题呢?以下是一些解决方案。

1. 使用 Array.find() 方法代替 Array.includes()

Array.find() 方法可以接受一个回调函数作为参数。这个函数将应用于数组中的每个元素,直到它找到一个值满足回调函数的条件。如果找到这样的值,则返回该值,否则返回 undefined。这通常是一种更可靠的比较方法。

以下是一个将 Array.find() 用于上面示例的方法:

2. 扩展 Array.prototype

你可以扩展 Array 对象的原型,并提供一个自定义的 includesDeep() 方法。这个方法将会使用深度优先的对象比较算法,以检查数组中是否存在一个给定的元素。

以下是一个实现这个方法的简单示例:

-- -------------------- ---- -------
---------------------------- - -------- -------- -
  ------ ---------------- -- -
    ------ ------------- --------
  --
-

-------- -------------- ------ -
  ----- ---- - --------------------------------------
  -- ----- --- -------------------------------------- ------ ------
  -- ---------- -------- -------- ----------------------- - -- ------ ----- --- ------
  ----- -------- - ---- --- -------- ------- - ------------ - --------------------------
  ----- -------- - ---- --- -------- ------- - ------------ - --------------------------
  -- --------- --- --------- ------ ------
  ----- ------- - -------- ------- ------ -
    ----- -------- - --------------------------------------
    -- ---------- -------- -------- --------------------------- -- -- -
      -- ---------------- ------- ------ ------
    -
    ---- -
      -- --------- --- -------------------------------------- ------ ------
      -- --------- --- -------- ----------- -
        -- ----------------- --- ----------------- ------ ------
      -
      ---- -
        -- ------ --- ------ ------ ------
      -
    -
  --
  -- ----- --- -------- -------- -
    --- ---- - - -- - - --------- ----
      -- ------------------- ---------- ------ ------
  -
  ---- -
    --- ------ --- -- ------ -
      -- --------------------------- -
        -- --------------------- ------------ ------ ------
      -
    -
  -
  ------ -----
-

由于这个方式可能会造成命名冲突,所以我们建议只在需要使用自定义 includesDeep() 方法的文件中添加这个方法。

使用 includesDeep() 方法将确保在比较数组元素和查找元素时使用深度比较算法。例如:

3. 使用 Lodash 库

Lodash 是一个流行的 JavaScript 实用程序库,包含数百个工具方法。其中一个工具是 _.isEqual(),它可以用于深度比较两个值。

以下是用 Lodash 中的 _.isEqual() 来改写上面的示例的一个例子:

_.some() 方法和 ECMAScript 2018 一样,都接受一个回调函数作为参数。当任何一个元素传递给回调函数并返回一个真值时,_.some() 跳出循环,并返回 true。使用 _.isEqual() 比较两个对象,以确保它们具有相同的内容。

结论

在使用 JavaScript 中的 Array.includes() 方法时,需要小心使用。这可能会导致错误的结果,导致应用程序的不稳定。

我们提供了三种不同的解决方案来避免这个问题。在使用任何这些方法时,都需要考虑到性能和可读性方面的因素,确保代码优雅、健壮和可扩展。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/66f6c545c5c563ced58bddb6

纠错
反馈