🙈

JavaScript の空配列を勘違いしていた

2021/05/12に公開3

JavaScript の空配列の真偽値について誤った理解をしていたので、自戒の念を込めて記事にしました。もしよかったら読んでみてください。

空配列の真偽値を理解する

まずは私の誤解していたケースから見ていきます。

// コード①
const foo = [];  // 空の配列

if (foo) {
    console.log("Hello");
} else {
    console.log("Bye");
}

// console.log で表示される結果
Hello

コード①のように if 文の条件が空配列の場合は、false とみなされ Bye が表示されると思っていました。しかし、実際には上記のサンプルコードでは true となり、Hello が表示されます。
それでは空配列の場合に false と判断させたい場合のコードを見てみましょう。

// コード②
const bar = []; // 空の配列

if (bar.length) {
    console.log("Hello");
} else {
    console.log("Bye");
}

// console.log で表示される結果
Bye

コード②のように、空配列の場合に false と判断させるには 配列.length と書く必要があります。これは JavaScript の言語仕様で、空配列は true として判断されるという仕様であるためです。なので配列に .length を利用することで配列内の値の数をもとに真偽値を導き出しています。
また、空配列のように true になる値を Truthy な値と言います。ちなみに Falsy な値も存在します。ここでは Truthy な値と Falsy な値について詳しく言及はしないので、気になる方は以下の資料をご覧ください。

もうひとつ私が Truthy な値として認識できていなかった空オブジェクトについても見ていきます。

空オブジェクトの真偽値について

// コード①
const foo = {}; // 空のオブジェクト

if (foo) {
    console.log("Hello");
} else {
    console.log("Bye");
}

// console.log で表示される結果
Hello
// コード②
const bar = {};  // 空のオブジェクト

if (Object.keys(bar).length) {
    console.log("Hello");
} else {
    console.log("Bye");
}

// console.log で表示される結果
Bye

こちらも先ほどの空配列と同様、空オブジェクトは Truthy な値とみなされるので true となり、Hello が表示されます。そこでオブジェクトの値の有無の判断には Object.keys(オブジェクト).length と書きます。こうすることでオブジェクト内のキー (key) の数をもとに真偽値を導き出し Bye が表示されます。

最後に

空配列と空オブジェクトの真偽値については JavaScript を書き始めて半年ほど経ってから知った事実でした。まだまだ JavaScript の言語理解を深めていかないといけないですね(汗)
また、今回の件は取り扱っている値が自分の認識と乖離してしまっていたということでもあるので、普段から取り扱う値への認識を適切にする姿勢を持たないといけないなと考えさせられた一件でもありました。

参考資料

Discussion

standard softwarestandard software

普段から認識を適切にするという意味ではこのように考えるといいかもしません。
私も何年もたってからわかってきたのですが

Truthy (True属性)判定の
if (array) は、
if (array == true) と同じで
(曖昧)等価演算子(==)をつかうことと同じなので、Booleanと確定される場面以外ではおすすめしません。

コツは常に厳密等価演算子(===)を使うことです。

if (array.length === 0)
と書くような癖をつけておいた方がJavaScriptを安全につかいこなせると思います。

なので、
1:BAD: if (array)
2:BAD: if (array.length)
3:GOOD:if (array.length === 0)
です。

lengthならば標準なので即座に読めるので、わざわざ、3:の書き方しなくて、2:の書き方でよい、と思うかもしれませんが、そこが罠で、独自プロパティでsizeとか、timeとか、そういうのになったときに、0が入るのか、'0'が入るのか、がわけわからなくなっているコードをよく見かけます。

if (objectA.size)
とかで、誤って size に '0' や、空配列が入って予期しない分岐に入ってしまって動きが見えなくなるということがスパゲティプログラムの中には非常にたくさんみかけました。

丁寧なプログラムを心がければ不具合は減っていくので、厳密等価演算子をおすすめします。

rynskerynske

コメントありがとうございます!
おっしゃる通り、等価演算子ではなく厳密等価演算子を用いる方が曖昧さを回避でき、より安全な実装ができますね。取り扱う値の認識を適切にするには必要な観点ですので勉強になりましたm(__)m

standard softwarestandard software

以前書いた記事です。参考になるかもです。

== null よりも ===null と === undefined を使おう - Qiita
https://qiita.com/standard-software/items/08597efad6dff1413897

文字数が減るという理由で等価演算子の省略による曖昧等価判定を好んで使う開発者がけっこう世の中多くて、それ故に市場に読んだり改良するのが苦しく不具合をすぐにみつけにくいコードがたくさんネット上にあふれていて、JSが難しく不具合を発生しやすい、と思われているような気がします。

そして不具合減らすための解決策としてTypeScript導入みたいな事になっているようにも思うのですが、丁寧にコード書いていけば、JSでも不具合を起こすなんてことは減っていきます。

厳密等価演算子の大事さが多くの人に知れ渡って、多くの人がちゃんと厳密等価演算子を書いてくれたら、プロジェクトの引き継ぎをしても、読むのが難しいコードが減るだろうに、と思ったりします。