ES9(ECMAScript 2018)引入了一个方便的方法 Array.includes()
,它可以检测一个数组是否包含某个元素。然而,在进行元素比较时,它会使用 JavaScript 的内置 SameValueZero
算法,这可能会导致错误。
在本文中,我们将介绍这个问题的背景和原因,并提供几种避免这个问题的方法。
问题的背景
Array.includes()
方法将使用 SameValueZero
算法去比较数组元素和待查找元素。简单说,如果两个值完全相同,则返回 true
。但是,这种比较可能不是我们想要的。
考虑如下示例,我们将两个对象添加到数组中,它们具有相同的内容但是却是不同的实例:
const arr = [{ id: 1 }, { id: 2 }]; const obj = { id: 1 }; console.log(arr.includes(obj)); // false
这个结果可能出乎意料。尽管数组中包含 id
属性值为 1 的对象,但是 Array.includes()
返回了 false
。这是因为 obj
对象和数组中的对象在 JavaScript 中是不同的实例。
这个问题可能在以下情况下产生:
- 在使用流行的 Redux 状态管理库时,通常需要在 Redux 中比较对象。如果你使用了
Array.includes()
,可能会遇到这个问题。 - 当你比较两个由不同组件传递到 React 组件时的对象时,也可能会遇到这个问题。
解决方案
现在我们已经了解了问题所在,那么如何避免这个问题呢?以下是一些解决方案。
1. 使用 Array.find() 方法代替 Array.includes()
Array.find()
方法可以接受一个回调函数作为参数。这个函数将应用于数组中的每个元素,直到它找到一个值满足回调函数的条件。如果找到这样的值,则返回该值,否则返回 undefined
。这通常是一种更可靠的比较方法。
以下是一个将 Array.find()
用于上面示例的方法:
const arr = [{ id: 1 }, { id: 2 }]; const obj = { id: 1 }; const res = arr.find((el) => el.id === obj.id); console.log(!!res); // true
2. 扩展 Array.prototype
你可以扩展 Array
对象的原型,并提供一个自定义的 includesDeep()
方法。这个方法将会使用深度优先的对象比较算法,以检查数组中是否存在一个给定的元素。
以下是一个实现这个方法的简单示例:
-- -------------------- ---- ------- ---------------------------- - -------- -------- - ------ ---------------- -- - ------ ------------- -------- -- - -------- -------------- ------ - ----- ---- - -------------------------------------- -- ----- --- -------------------------------------- ------ ------ -- ---------- -------- -------- ----------------------- - -- ------ ----- --- ------ ----- -------- - ---- --- -------- ------- - ------------ - -------------------------- ----- -------- - ---- --- -------- ------- - ------------ - -------------------------- -- --------- --- --------- ------ ------ ----- ------- - -------- ------- ------ - ----- -------- - -------------------------------------- -- ---------- -------- -------- --------------------------- -- -- - -- ---------------- ------- ------ ------ - ---- - -- --------- --- -------------------------------------- ------ ------ -- --------- --- -------- ----------- - -- ----------------- --- ----------------- ------ ------ - ---- - -- ------ --- ------ ------ ------ - - -- -- ----- --- -------- -------- - --- ---- - - -- - - --------- ---- -- ------------------- ---------- ------ ------ - ---- - --- ------ --- -- ------ - -- --------------------------- - -- --------------------- ------------ ------ ------ - - - ------ ----- -
由于这个方式可能会造成命名冲突,所以我们建议只在需要使用自定义 includesDeep()
方法的文件中添加这个方法。
使用 includesDeep()
方法将确保在比较数组元素和查找元素时使用深度比较算法。例如:
const arr = [{ id: 1 }, { id: 2 }]; const obj = { id: 1 }; console.log(arr.includesDeep(obj)); // true
3. 使用 Lodash 库
Lodash 是一个流行的 JavaScript 实用程序库,包含数百个工具方法。其中一个工具是 _.isEqual()
,它可以用于深度比较两个值。
以下是用 Lodash 中的 _.isEqual()
来改写上面的示例的一个例子:
const arr = [{ id: 1 }, { id: 2 }]; const obj = { id: 1 }; console.log(_.some(arr, (el) => _.isEqual(el, obj))); // true
_.some()
方法和 ECMAScript 2018 一样,都接受一个回调函数作为参数。当任何一个元素传递给回调函数并返回一个真值时,_.some()
跳出循环,并返回 true
。使用 _.isEqual()
比较两个对象,以确保它们具有相同的内容。
结论
在使用 JavaScript 中的 Array.includes()
方法时,需要小心使用。这可能会导致错误的结果,导致应用程序的不稳定。
我们提供了三种不同的解决方案来避免这个问题。在使用任何这些方法时,都需要考虑到性能和可读性方面的因素,确保代码优雅、健壮和可扩展。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/66f6c545c5c563ced58bddb6