Skip to content

JavaScript難しい

Published: at 11:52

何回も間違えて、そして何度も理解した気になるTruthyと論理和、論理積。

Table of Contents

Open Table of Contents

空配列はtruthy

空配列の[]やオブジェクトの{}はTruthy。

なんか納得できないのは私だけでしょうか?

まぁそういうものだと言われたら納得するしかない。こういうプログラミング言語の成り立ちとか専門で勉強してきたわけではないしそういう大学にいったわけでもないからわかんなくて良いんやけど、やっぱり理由気になるよね。

ちなみに、これで今回自分は何回目かわからないバグを踏んでいた。というのも、arrayがnull | undefined | arrayの型になっていたので、arrayがあったら表示しようみたいなことをしていた。この時はnullやundefinedでないことを確認したかったのでこれでいいと思っていた。

コードはこんな感じ。

<div>
  {array && ( // array = []
    <h1>配列に値があれば表示<h1>
    // さらに内部でmapしている。
  )}
</div>

この条件だとずっと配列に値があれば表示が表示されていて、テストに失敗していた。調べてたら空の配列もTruthyということに気づいた。。 今まで空の配列はなぜかfalsyだと思ってたので、恥ずかしい限りである。

ひとまずこんな感じで変えて回避した。

<div>
  {array && array.length > 0 && (
    <h1>配列に値があれば表示<h1>
    // さらに内部でmapしている。
  )}
</div>

論理積、論理和を条件で使いたい場合はbooleanになるようにしなくてはいけないなって思ってるのに忘れてしまう。 この場合条件で使いたかったというかは存在確認したかっただけなのだが、まさか空配列もTruthyだとは。😨

ちなみに空配列はtruthyだけど、[] == falseだとtrueになる。(===じゃないよ)。理由はプリミティブなfalseとゆるく比較する場合は[]が""のに変換されて、さらに""とboolだとどちらも数値になって0になるから比較するとtrueになるらしい。

[] は truthy ですが、false と緩く等しいです。すべてのオブジェクトは truthy であるため、[] も truthy です。しかし、プリミティブである false と比較する場合、 [] も Array.prototype.toString() によって "" というプリミティブに変換されます。文字列と論理値を比較すると、どちらも数値に変換され、どちらも 0 になるので、[] == false は true となります。一般に、falsy であることと == false は次のようなケースで異なります。 参考

今回ので知れたからこの失敗を忘れないようにいこうと思う。

Falsyな値

ということでfalsyな値をおさらいしてみた。

mdn web docs によると、null, undefined, false, NaN, 0, -0, 0n, "", document.allがfalsyもうこれ以外はtruthy!!細かいところはまだあるみたいだけど使わなそうなので一旦ここら辺覚えておけば良さそう。

falsyだと条件式とかでは偽になるから、条件式とかでは実行されない。

if (null) {
  console.log('hello');
}

なのでこれらの値がある場合はJavaScriptでは偽になる。

JSの論理積、論理和

今回踏んだバグとはちょっと条件は違うけど、これも結構間違いやすい。 というか、truthy, falsyを理解してないと事故る。罠すぎるよね。便利なんだけどbooleanのみ許可するとかしてほしいよね。Swiftとかだとbooleanしか入れれなかった気がする。

論理積は&&、論理和は||のやつ。

動作的なところだと、論理積なら全てがtruthyなら最後の値を返す、どこかでfalsyになれば即座にその値を返す。論理和は1つ以上truthyならその値を返す。 間違いやすいのが、「オペランドの値を返す」というところ。true, falseなら別に問題はないが、文字列や数字など他の値が返ることもある。

その結果、条件式でfalseだと期待しているのに文字列が返ってきていてtrueになってない!!みたいなことが稀に起こる。

とりあえず大事なのが、最後に評価されたオペランドの値を返すこれだけ覚えておけばなんとかなるのでは? true, falseが返ることもあるがとりあえずその値が返ると覚えておけばそれでいいか悪いかの判断ができるはず(多分)

短絡評価されるとかもあるけど、そこに関してはすんなりと理解できたからもはやどうでもいい。

そもそもBooleanに変換するか、Booleanの結果が出るように条件式を書いた方がいい

整理するとこんな感じ。

true && '最高'; // output: '最高'
true && 3150 && true; // output: true
false || '32' || true; // output: "32"

別にこれでも問題があるわけではないが、条件式で使う場合にboolean以外の値が混じってバグる可能性があるからそもそもBooleanになるようにすれば少なくとも意図しないバグは減らせる。 配列に関しても、空がtruthyになるから、length > 0でbooleanにすればいいだけ。あとはBooleanとかで囲っちゃうことかな。

true && Boolean('最高'); // output: true

実際、&&||で値を返せるというのは便利。値があればコンポーネントを表示するとか、値が無ければデフォルトの値を表示するとかに使える。達人ならもっといろんな便利なことに使えるんだろうけどわいの脳みそだとこのぐらいしか思いつかん。笑

最後に

値を返したいなら値でもいいが、そうでないなら条件式書く! あとプリミティブとかよくわからんし、やはり基礎的な知識が欠けているなと感じるからとりあえずMDNのHTML, CSS, JavaScript改めて学習し直さなければ

もう二度と忘れない!!!