JavaScript初心者の勘違い
JavaScriptを学ぶ中で、「なんとなくこうだろう」と思っていたことについて、仕様や実際の挙動をもとに整理し基礎を固めていくシリーズです。
「自分も同じ勘違いをしていた!」という方の参考になれば嬉しいです。
はじめに
前回、「0 == falseがなぜtrueになるのか」について、==での評価方法を
順に追いながら学習しました。
(前回記事はこちら)
今回は、私が勘違いしたもう一つの記述"false" == falseについて、
前回同様に間違った自分の解釈と正しい考え方についてまとめます。
"false" == false
自分の解釈(間違い)
"false" == false
- StringとBooleanの比較なので、Boolean→Numberに変換し右辺は0
→"false" == 0(ここまでは正しい) - StringとNumberの比較になるのでString→Numberに変換する
→Number("false")で、引数のStringが空文字""ではないためtrueと
判定すると考えてしまいました(ここから間違い)。
→その結果、Number(true)となり結果は1 -
0 == 1のため結果はfalse
1つめのBoolean→Numberの型変換(Number(false))の結果は正しく考えられました。
しかし、2つめのString→Numberの型変換では、Number("false")にTruthy/Falsyの
考え方を適用してしまいました。
Number("false")では「Truthy/Falsy」で判定を行わず、数値に解釈できるか否かにより結果
を決定します。
正しい考え方
- 「空文字
""の場合はfalse、それ以外はtrue」というのはTruthy/Falsyの考え方
→Truthy/Falsyの考え方は条件式やBoolean型での話で今回は関係ない -
Number()関数ではNumber型に変換できない引数の場合NaNを返す
→Number("false")はNaNとなる - NaNは何とも比較できない
→NaN == 0となり比較できないため、結果はfalse
まとめると、実際は以下のように評価されます。
"false" == false
(1) Boolean→Numberへの型変換
StringとBooleanの比較なので、Boolean→Numberに変換し右辺は0となります。
→"false" == 0
(2) String→Numberに変換する
StringとNumberの比較となるのでString→Numberへ変換します。
Number("false")で型変換を試みますが、引数"false"は数値に変換できない文字列のため
結果はNaNとなります。
→NaN == 0
(3) NaNとの比較
NaNは何とも比較できないため、結果はfalseとなります。
そもそもTruthy/Falsyな値とは
条件式やBoolean型でtrue/falseとして扱われる値のことです。
備忘録も兼ねて、以下にFalsyな値をまとめました。
| 値 | データ型 | 値 | データ型 |
|---|---|---|---|
| false | Boolean | null | null |
| 0、-0 | Number | undefined | undefined |
| 0n | BigInt | NaN | NaN |
| "" | String |
上記以外はTruthyな値となります。
例えば、
Boolean(0);
Boolean("");
はfalseとなります。
Number型への変換
Number関数は、引数で与えられた文字列を数値に変換する関数です。
今回のように、数字以外の文字列を引数として渡すとNaNを返します。
例えば、
Number("数値ではありません")
とするとNaNが返ります。
NaNとは
「Not a Number」の略で、Number型に変換できない という性質を表します。
Numberではないと言っていますがNumber型のデータです。
typeof(NaN) // => Number
NaNを含む多くの演算結果はNaNになります。
1 + NaN // => NaN
const a = NaN;
console.log(a); // => NaN
また、NaNは何とも比較できずfalseを返します。
例えば、
NaN == 0
NaN == undefined
ではfalseが返ります。
自分自身とも一致しない
NaN == NaN、NaN === NaNとしてもfalseが返ります。
何とも比較できない性質のためです。
NaNかどうかの判定方法
Number.isNaN()を利用します。
引数が数値かつNaNである場合にtrueを返し、そうでなければfalseを返す関数です。
Number.isNaN(NaN); // => true
Number.isNaN(1); // => false
他にもisNaN()で判定する方法があります。
こちらは引数が数値でなければNumber型に変換したあとでNaNかどうかを判定し結果を返します。
isNaN("文字列です"); // => Number("文字列です")の結果がNaNのためtrue
isNaN(""); // => Number("")の結果は0で数値のためNaNではなくfalse
isNaN(undefined); // => Number(undeined)の結果はNaNのためtrue
3つめの記述で、undefinedはNaNではないためfalseを返してほしいのですが、
結果はtrueとなります。
引数に対してNaNかどうかを判定する前に内部的にNumber型に変換されるので、
これにより意図した判定ができない場合があります。
そもそもNaNはデータ型としてはNumber型のため、Number型であるかも同時に確認
するNumber.isNaN()を用いて厳格に判定することが適切だといえます。
おわりに
今回は「Truthy/Falsy」と「Number型への変換」を混同していたことに気付きました。
学べば学ぶほど知識が増え、一度整理できたと思っても別の知識と混ざってしまうことがあります。
今回も周辺知識を含めて整理し直すことで、自分の理解が深まったと感じています。
次回
次回はChatGPTから出題された、初心者が勘違いしやすいデータ型の比較に関する問題を
解説していきたいと思います。
次回記事はこちら
参考