Array.someとArray.everyを空の配列で実行するとどうなる？

# はじめに
`Array.some`と`Array.every`、どちらも配列においてとても便利なメソッドですね。
自分も幾度となく使っていてお世話になっています。
そんな頻出のメソッドではありますが、空の配列だった時の挙動がちょっと意外だったので備忘録も兼ねてまとめてみました。

# 前提：`Array.some`と`Array.every`って何？
日々JavaScriptと戦っている方なら解説不要かと思いますが、一応記述しておきます。

<dl>
  <dt><code>Array.some(callbackFn)</code></dt>
  <dd>
    配列の要素それぞれで<code>callbackFn</code>を実行し、<code>true</code>を返す要素が一つでもあれば<code>true</code>を返し、そうでなければ<code>false</code>を返す。<br>
    砕いて言うと、<strong>配列の中で条件を満たすものが一つでもあればOKとする</strong> ということ。
  </dd>
  <dt><code>Array.every(callbackFn)</code></dt>
  <dd>
    配列の要素それぞれで<code>callbackFn</code>を実行し、全ての要素で<code>true</code>が返されれば<code>true</code>を返し、そうでなければ<code>false</code>を返す。<br>
    砕いて言うと、<strong>配列の全てで条件を満たせばOKとする</strong> ということ。
  </dd>
</dl>

```javascript
[1, 3, 10].some((x) => { return x > 5; });
// true
[1, 3, 5].some((x) => { return x > 5; });
// false

[6, 8, 10].every((x) => { return x > 5; });
// true
[6, 8, 1].every((x) => { return x > 5; });
// false
```

# 結果
というわけでタイトルのお話に戻りますが、結果は下記のようになります。

```javascript
[].some((x) => { return x > 5; });
// false

[].every((x) => { return x > 5; });
// true
```

**...あれ？**
`Array.some`は分かります。空配列なら`true`を返す要素が一つもないので。
`Array.every`はなんでそうなったんだ？？おお？？
**君は空のカゴを指して「カゴの中に入っている物は全部りんごですか？」って聞かれたら「はい！そうです！」って言うのか？？？**
これは納得できない。こんなこと言ったら間違いなく周りから眉をひそめられます。
もう某魔法使いの物語の最後の戦いでルーピ〇とト〇クスが死んだ時くらいに納得できない。あれはなぜ？

# 実際なぜこうなるのか？
<font color=red>**そういう風に定義したからです。**</font>

 　
...というのは無いと思うので、ちゃんと調べてみました。
とりあえずMDNでも見てみましょう。

> every は数学における「∀ （すべての / for all）」記号と同様のふるまいをします。特に、空の配列に対しては true を返します。（空集合のすべての要素が与えられた任意の条件を満たすことは空虚に真です。）
（[Array.prototype.every()#解説 MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/every#%E8%A7%A3%E8%AA%AC) より）

なるほど！...か？
となりましたが、「空虚な真」という言葉を調べてみると、要は**命題の前件が偽なら後件の真偽に関わらず命題は真とする**ということだそうです。
つまり、`Array.every`で空の配列を渡された時点で命題の前件は配列が空＝偽になり、`callbackFn`による評価は無関係に命題は空虚な真となる、つまり`true`が返されるということですね。ほ～

~~よし、これからは空のカゴを指して「カゴの中に入っている物は全部りんごですか？」って聞かれても「はい！そうです！」って元気に答えるぞ！~~

<details><summary>空集合について</summary>
この記事を書く時に<a href="https://zenn.dev/wsuzume/articles/c4f85df441def6">この記事</a>を見つけたのですが、空の配列を空集合(∅)と捉えることで<code>true</code>が返されるべき、という結論に納得することができました。<br>
集合については<ins>あらゆる任意の集合は空集合を部分集合に含んでいる</ins>という基礎が記憶がわずかにある程度だったので、流石にこの部分を自分で記述するのはもっと詳しい人が既に解説してくれていることもあり気が引けました。。。<br>
ただ、<a href="https://zenn.dev/link/comments/e5aa5368fded44">このコメント</a>にあった X ⊂ A は成り立っても X ⊂ B は成り立たない理由は面白かったです。ありがとうございました。
</details>

# そもそもの話

前半で`Array.every`について**配列の全てで条件を満たせばOKとする**と書きましたが、この表現自体がそもそも違っていた様子でした。
いや間違ってないのかもしれないけど、自然言語としては導かれた結果からすると明らかにおかしいですね。
書き換えるなら**配列の中で条件を満たさないものが一つも無ければOKとする**という表現になるでしょう。これなら空配列で`true`が返されても納得です。

...ということなんですが、そもそもMDNにはちゃんと記載されていました。
>callbackFn 関数がいずれかの要素で偽値を返した場合は、すぐに false を返します。それ以外は true です。
（[Array.prototype.every()#返値 MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/every#%E8%BF%94%E5%80%A4) より）

*every*というメソッド名からは直感的に連想できないような表現になりますが、挙動から考えるとこれなら間違えないですね。
途中の「カゴの中に入っている物は全部りんごですか？」という質問も、`Array.every`さんは**実は「カゴの中に入っている物にりんご以外は含まれていないですか？」と聞かれていた**ということでした。
言葉で覚えるのは人間なので当然ですが、ちょっとした表現の違いで誤解が出るな～と思うと難しいですね。

# 余談
`Array.every`と同様のメソッドは他の言語でもありますが、Pythonの`all(iterable)`やRustの`Iterator::all`、Javaの`arrayList.stream().allMatch`も同様に空配列だと`(True)true`を返すようです。
プログラミング言語の中ではこれが一般的なんですねー

# 最後に
ということで、メソッドの解釈や覚え方には気を付けようという教訓でした。あとは空配列のようなイレギュラーケースについては特に確認すべきということも。
また、思いっきりすっ飛ばしましたが`Array.some`がなぜ空配列だと`false`なのか？もちゃんと理由があるようなのですが、今回はここまでとします。
ちょっとした事象ですが、調べると奥が深くてまだまだ分からないことだらけだと痛感する出来事でした。これからも頑張って少しずつ理解していきます。

# 参考リンク
- [Array.prototype.some() MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
- [Array.prototype.every() MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/every)
- [空集合 Wikipedia](https://ja.wikipedia.org/wiki/%E7%A9%BA%E9%9B%86%E5%90%88)
- [空虚な真 Wikipedia](https://ja.wikipedia.org/wiki/%E7%A9%BA%E8%99%9A%E3%81%AA%E7%9C%9F)