JavaScript数组方法--如何在JS中使用every()和some()

141 阅读6分钟

在JavaScript中,everysome 可以帮助你测试某个东西对数组中的每个元素或某些元素是否为真。

在这篇文章中,我将告诉你如何使用这些有用的数组方法。

1 every()some() 如何工作 - 概述

首先,我们需要一些数据来测试。为了简单起见,我们考虑一个数字数组:

const nums = [34, 2, 48, 91, 12, 32];

现在我们假设要测试数组中的每个数字是否小于100 。使用every ,我们可以很容易地进行测试,如下所示:

nums.every(n => n < 100);
// true

又短又好!你可以这样想,这里发生的事情是这样的:

  • every 在数组元素上从左到右循环。
    • 对于每一个迭代,它调用给定的函数,以当前数组元素作为它的第一个参数。
    • 循环一直持续到该函数返回一个**错误的值**。在这种情况下,every 返回false - 否则返回true

some 循环的工作方式也与 非常相似。every

  • some 在数组元素上从左到右循环。
    • 对于每个迭代,它调用给定的函数,并将当前数组元素作为其第一个参数。
    • 循环一直持续到该函数返回一个**真值**。在这种情况下,some 返回true - 否则返回false

现在让我们用some 来测试数组中的某个数字是否为奇数:

nums.some(n => n % 2 == 1);
// true

这确实是真的!91 是奇数。

但这并不是故事的结束。这些方法还有一些深度。让我们深入了解一下。

2 everysome#的参数

使用everysome 数组方法的方法是完全一样的。它们有相同的参数集,这些参数的含义也是相同的。所以,要想一下子学会它们是非常容易的。

我们已经使用了这些方法的第一个参数,它是一个函数。我们称这个函数为谓词

在计算机科学中,**谓词**是一组参数的函数,返回一个布尔值作为答案。JavaScript把我们给every/some 的函数当作一个谓词。我们可以返回任何类型的值,但那些都被当作布尔值,所以通常把这个函数称为谓词。

它们还有一个可选的第二参数,用于控制非箭头谓词中的this 。我们称它为thisArg

所以你可以通过以下方式调用这些方法:

arr.every(predicate)
arr.every(predicate, thisArg)

arr.some(predicate)
arr.some(predicate, thisArg)

下面我们来看看predicate 和可选的thisArg 的详细情况。

2.1predicate

通过predicate,every/some ,不仅可以让我们访问当前的数组元素,还可以通过其参数访问其索引和原始数组,如下所示:

  • 第一个参数:当前的数组元素。
  • 第二个参数:当前元素的索引.
  • 第三个参数:调用every/some 的数组本身。

在前面的例子中我们只看到第一个参数的作用。让我们通过定义另外两个参数来抓住索引和数组。这一次,假设我们有一些T-Shirt数据来测试是否所有的T-Shirt都有freeCodeCampe

let tshirts = [
  { size: "S", color: "black", logo: "freeCodeCamp" },
  { size: "S", color: "white", logo: "freeCodeCamp" },
  { size: "S", color: "teal",  logo: "freeCodeCamp" },
  { size: "M", color: "black", logo: "freeCodeCamp" },
  { size: "M", color: "white", logo: "freeCodeCamp" },
  { size: "M", color: "teal",  logo: "freeCodeCamp" },
  { size: "L", color: "black", logo: "freeCodeCamp" },
  { size: "L", color: "white", logo: "freeCodeCamp" },
  { size: "L", color: "teal",  logo: "freeCodeCamp" },
];

tshirts.every((item, i, arr) => {
  console.log(i);
  console.log(arr);
  return item.logo == "freeCodeCamp";
})

在你的控制台中试一下,看看输出结果。不要忘了也玩一下some

2.可选的 thisArg#

如果在任何情况下你需要在你的谓词里面有一个特定的this 值,你可以用thisArg 。注意这只适用于非箭头谓词,因为箭头函数没有this 绑定。

如果你省略了这个参数,this 在谓词(非箭头函数)里面照常工作,也就是说:

  • 在严格模式下,thisundefined
  • 在马虎模式下,this全局对象,在浏览器中是window ,在Node中是global

我想不出任何关于thisArg 的好用例。但我认为它的存在是好的,因为现在你可以在你的谓词中控制this 。因此,即使有一天需要用到它,你也会知道有一个方法。

如果你有任何关于使用thisArg 的好主意,请在Twitter上告诉我 :)

3 everysome#的边缘案例

3.1当everysome 在一个空数组上被调用时会发生什么?

有时你想测试的数组可能是空的。例如, 你从一个API中获取了一个数组, 它在不同的时候可以有任意数量的元素, 包括0.

对于every ,一个true 的返回值可能意味着两种情况:

  • 如果数组有超过零的元素,那么数组的所有元素都满足谓词。
  • 数组没有任何元素。

所以如果我们想的话,我们可以在谓词里面做一些疯狂的事情,就像下面这样:

wth-what-the-hell-is-going-on

const myCatsBankAccounts = [];
myCatsBankAccounts.every(account => account.balance > elonMusk.totalWealth)

并且仍然得到true 作为返回值!

如果数组是空的,JavaScript直接返回true ,而不需要调用任何谓词。

这是因为在逻辑学中,你可以对空集的元素说任何话,而这被认为是真实的,或者更确切地说,是空的真实。这样的逻辑在日常使用中可能显得很无稽,但这就是逻辑的工作方式。阅读上面链接的维基页面以了解更多信息。

所以,如果你得到true ,作为every 的返回值,你应该注意到这个数组可能是空的。

some 另一方面,在空数组上直接返回 ,不需要调用 ,也没有任何奇怪的地方。false predicate

3.2不存在的元素会被忽略

如果你的数组里有像下面这样的洞,它们会被every/some 忽略:

const myUntiddyArry = [1,,,3,,42];

3.3篡改谓词中的数组

我不会在这里讨论这种情况,因为在大多数情况下,突变原始数组只会使事情复杂化,为bug提供更多空间。

如果你真的需要或有兴趣,请阅读规范中的说明以了解细节。

4给你一个挑战

在JavaScript中用some ,用some ,用every 来表达every

我希望你也能感受到我在发现这种关系时得到的巨大快乐和惊奇!

解决方案

让我们一步一步来吧。首先让我们尝试用some 来表达every

  • 对于数组的每个元素,谓词都是真的。
  • 对于数组中的某些元素,谓词不为真,这不是真的。

我们可以像下面这样把它翻译成JavaScript:

const myEvery = (arr, predicate) => !arr.some(e => !predicate(e));

现在让我们用every 来表达some 。这和之前几乎一样。只是someevery 所取代。试着去理解发生了什么:

  • 对于数组中的某些元素,该谓词是真的。
  • 对于数组中的每个元素,谓词都不是真的。

在JavaScript中:

const mySome = (arr, predicate) => !arr.every(e => !predicate(e));

请注意,当arr 是空的时候,上述的实现也是有效的。而且为了简单起见,我排除了predicatethisArg 的其他参数。如果你有兴趣,可以尝试自己添加这些细节。在这个过程中,你可能会学到一件或几件事情!