【问题标题】:array .includes() giving unexpected behavior数组 .includes() 给出意外行为
【发布时间】:2021-04-07 13:42:24
【问题描述】:

我有一个非常简单的数组,正在检查它是否 .includes() 一个值。但它没有返回我期望的结果。

var myArray = [['noca', 'North Cascades National Park'], ['shen', 'Shenandoah National Park']];

var myItem = ['noca', 'North Cascades National Park'];

myArray.includes(myItem);   //returns false

为什么myArray.inclues(myItem) 返回假?这似乎是世界上最简单的事情。它应该返回 true。

【问题讨论】:

  • 因为['noca'] === ['noca'] 是false。这是内存中两个不同的数组。你不能用这种方式比较数组。
  • 看起来很简单,但实际上并不是最简单的 =)。这是一个很好的问题,希望这对其他人有帮助!

标签: javascript arrays


【解决方案1】:

检查一个数组是否包含另一个数组很棘手。正如我在 cmets 中所说,['noca'] === ['noca'] 返回false,因为这是两个不同的数组。

另一方面,JSON.stringify(['noca']) === JSON.stringify(['noca']) 返回 true 因为它比较两个字符串,所以你可以使用它:

var myArray = [['noca', 'North Cascades National Park'], ['shen', 'Shenandoah National Park']];
var myItem = ['noca', 'North Cascades National Park'];

const checkContains = (parent, child) => parent.some(arr => JSON.stringify(arr)===JSON.stringify(child))

console.log( checkContains(myArray, myItem) )
console.log( checkContains(myArray, ["test"]) )
console.log( checkContains(myArray, ["noca"]) ) // No false positive (works as intended)

【讨论】:

  • 这也是一个不错的方法。我会使用这个或我发布的答案。两者都会给你相同的结果。这个可能会快一点,因为它的复杂性较低,尽管我不确定 JSON.stringify 的性能。
  • 目前是对每个父元素都进行字符串化,也就是说如果父元素包含100个元素,比较数组会被字符串化100次,这显然是一种资源浪费。我会通过缓存JSON.stringify(child) 来优化它。代码有点多。
  • 啊,明白了。我认为 .some 成功后会立即返回,因此虽然最坏的情况非常糟糕,但平均情况可能会好得多。
【解决方案2】:

从这个答案中采用以下内容:

https://stackoverflow.com/a/48538239/2096053

var datas= [
  ["aaa", "bbb"],
  ["ddd", "eee"]
];

function exists(arr, search) {
    return arr.some(row => 
        Array.isArray(row) &&
        Array.isArray(search) &&
        row.length === search.length &&
        row.every((val, index) => val === search[index])
)
};

console.log(exists(datas, ['aaa', 'bbb'])); // TRUE
console.log(exists(datas, ['aaa']));        // FALSE
console.log(exists(datas, ['xxx']));        // FALSE
console.log(exists(datas, 'xxx'));          // FALSE

您需要结合使用some 和includes 才能正确遍历数组。

我已更新此答案以搜索数组。

【讨论】:

  • 据我了解,OP 想检查datas 是否包含["aaa", "bbb"]。他们正在尝试做myArray.includes(['noca', 'North Cascades National Park']);
  • @JeremyThille 我更新了使用数组的答案 =)
  • 在大多数情况下有效。但它也会返回误报。 exists(datas, ['aaa']) 返回true。你必须row => search.every(v => row.includes(v)) && row.every(v => search.includes(v))。但这是很多数组遍历。
  • @JeremyThille 你是对的,我在处理这个问题时做得更好,而且在非数组搜索时也不会出错。
  • 很公平 :) 现在它确实有效。点个赞
【解决方案3】:

这是一个预期的行为,因为数组是一个对象并且它被引用。因此,您的数组元素和要比较的实际元素不相等,Array.prototype.includes() 将返回 false。

如果您尝试关注,它将返回true。

var myItem = ['noca', 'North Cascades National Park'];

var myArray = [myItem, ['shen', 'Shenandoah National Park']];

myArray.includes(myItem);   //returns true

【讨论】:

  • 这是一个很好的解释,但它并不能解决实际问题。如果myArray 不包含myItem 怎么办?
  • 要解决这个问题,基本上你需要使用JSON.stringify()或者Lodash的cloneDeep方法来序列化你的目标元素。您可以通过将每个序列化数组元素与序列化目标元素进行比较来使用Array.prototype.some()。 var myItem = ['noca', 'North Cascades National Park']; var myArray = [['noca', 'North Cascades National Park'], ['shen', 'Shenandoah National Park']]; myArray.some(el => JSON.stringify(el) === JSON.stringify(myItem)); //returns true
  • 是的,这应该是你的答案......当你打字的时候,我自己把它作为答案发布了:)
【解决方案4】:

您没有正确使用它。数组之间的引用不一样。

查看文档:includes

您应该遍历数组并使用 every 例如。

【讨论】:

  • 这是评论,不是答案。您只是指出资源并提供链接。
  • @JeremyThille,说得好。下次会做得更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-08
  • 1970-01-01
  • 2011-12-01
  • 1970-01-01
相关资源
最近更新 更多