JavaScript: 不思議な真偽値

JavaScript は, あらゆる値を真偽値判定に使えます。しかし、偽になる値は限定されています。

値または型 真偽値
undefined 偽.
null 偽.
Boolean 型 その値どおり. true は真, false は偽.
Number 型 +0, -0 および NaN は偽. その他は真.
String 型 空文字列 "" は偽. その他は真.
Symbol 型 真.
Object 型 真.

0 が偽というのは C言語っぽい。BigInt 型の 0n も "偽" になる。

空文字列が偽になる一方で, 空配列 [] は "真" になる.空オブジェクト {} も真. Common Lisp では空リストも偽になるので、JavaScript はそれとは異なる流派ということになる。

true, false との比較

真偽値の代表的な値は true, false です。これらと比較したらどうなるか。

文字列 "0" は真. 空配列も同様。でも, "0" == false もまた真になる。暗黙の型変換は意外なことが起こる。この点でも, == はもはや使ってはならない。

== true == false === true === false
undefined false false false false
null false false false false
false false true false true
true true false true false
0 false true false false
1 true false false false
NaN false false false false
Infinity false false false false
"" false true false false
"0" false true false false
"1" true false false false
[] false true false false
{} false false false false

undefined, null, NaN, "" は, 偽にも関わらず, false との比較ではイコールになりません。したがって、真偽値を確認するのに, true とも false とも比較してはいけません。

真値を true に, 偽値を false に変換

true とも false とも比較すべきでないなら、どうするか。

Boolean() を使えばよい。あるいは, !! でもよい。

new Boolean() でないことに注意。プリミティブ値のクラスをnew するのは意味がないどころか正常にうごかない。実行時エラーにならないので、注意するしかない。こういうのはエラーにしてほしい。

Number() や String() に渡したら?

数値や文字列に変換するとどうなるか。

Number() String()
undefined NaN "undefined"
null 0 "null"
false 0 "false"
true 1 "true"
0 0 "0"
1 1 "1"
NaN NaN "NaN"
Infinity Infinity "Infinity"
"" 0 ""
"0" 0 "0"
"1" 1 "1"
[] 0 ""
{} NaN "[object Object]"

Number() の値が混乱している。偽値のうち undefined, NaNNaN になるのは分かる。そうであるならどうして, null が0 になるんだ。

{}NaN になる一方で, [] が 0になる。何なんだ。

parseInt(str, radix) は, また違った結果になる。null, undefined, false, "", [], {} ともすべて NaN になる。

文字列 "TRUE" または "FALSE" を真偽値に変換

いろんなやり方が考えられるが, JSON.parse() を使うのはやりすぎ。

例えば, 次のような方法が考えられる。

JavaScript
[RAW]
  1. function toBool(str) {
  2. if (str === null || str === undefined)
  3. return null;
  4. if (typeof str === "string") {
  5. switch( str.trim().toLowerCase() )
  6. {
  7. case "true": case "yes": case "1": return true;
  8. case "false": case "no": case "0": return false;
  9. default: break;
  10. }
  11. }
  12. return Boolean(str);
  13. }
  14. console.log(toBool(), toBool("True"), toBool("FALSE"), toBool("hoge"));
  15. //=> null true false true