初心者の方が JS で真偽判定はする際にハマりやすい点を、ごくごく基本的なものから順に 7 つまとめました。
※ 記事の最後に中上級者向けのクイズもあるので、是非プレイしてみてください。
#1. else if のスペース
まずは基本中の基本からですが、他言語のようにelseif
と詰めて書くと SyntaxError
になります。
もちろんelif
もダメです🐍
#2. 配列かどうかの判定
文字列や数値であればtypeof
で判定できるのですが、配列の場合は 'object' と判定されてしまうので使えません。
そのためArray.isArray()
を使います。
const a = [1, 2]
console.log(typeof a) // => 'object'
console.log(Array.isArray(a)) // => true
#3. 配列が空かどうかの判定
文字列とは異なり、配列は空でも真と扱われるため!array
のようには判定できません。
そのため配列の長さが 0 かどうかで判定します。
const arr = []
console.log(!arr) // => false
console.log(!arr.length) // => true
if(!arr.length) {
console.log('空です')
}
#4. オブジェクトが空かどうかの判定
配列と同様、空のオブジェクトも真として扱われます。
さらにオブジェクトには length プロパティがありません。
そのため、Object.keys(obj)
で全てのキーを配列で取得し、
その配列の長さが 0 かどうかをみます。
const obj = {key1: 1, key2: 2}
console.log(Object.keys(obj)) // => ["key1", "key2"]
if( Object.keys(obj).length ) {
console.log('空じゃないよ')
}
#5. 配列やオブジェクトが等しいことの判定
配列やオブジェクトの中身が等しいことの判定に===
を用いることはできません。
実際、以下の式はfalse
になります。
const a = [1, 2]
const b = [1, 2]
console.log(a === b) // => false
確かにa
から要素を削除してもb
は何も変化しないですし、両者を「異なる対象」と判定するのは妥当と言えます。
では、両者の中身が等しいかを判定するにはどうすればいいのかというと、どうも簡単かつ確実な方法は用意されてないようです。
自力で判定用関数をゴリゴリ作ってもいいですが、ササっとやりたい場合はLodashなどのプラグインを使うのがよさそうです。
#6. 普通の数値かどうかの判定
つまりInfinity
でもNaN
でもない、普通の数であるかを判定したい場合です。
次のNaN
判定コードは想定通りには動きません。
if(num === NaN){
console.log('NaNです(?)')
}
なぜかというと JS の仕様ではNaN === NaN
はfalse
だからです。
(というかNaN
はいかなる値と比較してもfalse
となります)
なのでNumber.isFinite()
を使います。
Number.isFinite(aug)
は、aug
が±Infinity
およびNaN
でない数値の場合のみtrue
を返してくれます。
if( Number.isFinite(num) ) {
console.log('numは普通の数値です')
}
※IEではNumber.isFinite()
はサポートされていません。代わりにisFinite()
が使用できます。
#7. 大きな数に関する判定
JSでは正確に扱える数の上限が決められています(253 - 1 = 9007199254740991)。
この上限を超えた数を使った計算は、正確性が保証されません。
計算中にこの上限を超過し、数値が不正確な値に変化してもエラーは出ないため、意図しない動作が生じえます。
###実際的な例
以下は、私がエンジニア1年目のころに経験した例(を単純化したもの)です。
まず、次のような仕様の IC カードがあるとします。
- 各カードには 16 桁の ID が振られている(例:319A-F3D5-EAE2-55E7)
- 正しい形式の ID は、16 進数の整数に変換したとき 10 で割り切れる。
例えば、
ID: 319A-F3D5-EAE2-55E7
からハイフンを除去し、16進法としてみると、
319AF3D5EAE255E7
になりますが、これは 10 進法で
3574437354366195175
で 10 で割り切れないため、不正な ID であることがわかります。
一見すると、このカード ID の正当性をチェックするには、ID をparseInt()
で変換して 10 で割れるか調べればいいだけに思えます。
// id取得、ハイフン除去などは省略
console.log(id) // => "319AF3D5EAE255E7"
const num = parseInt(id, 16)
if(num % 10 !== 0) {
throw new Error('不正なIDです')
}
しかしのコードをテストをしてみると、どんな ID もチェックを通り抜けてしまい、うまくいきません。
これはなぜかというと、16 桁の ID をparseInt()
で変換したとき値が大きくなりすぎて、下何桁かが 0 に丸められてしまうためです。
最下桁が0に丸められた結果、必ず10で割り切れるようになるため、常に「正しい形式」だと判定されてしまうわけです。
###大きな数を扱うためには
将来的には大きな数が扱える BigInt が仕様に入るみたいですが、2018年12月現在ではBigInteger.jsといったプラグインを用いるしかないようです。
#おまけ
中上級者の方のためにJavaScript 真偽判定クイズを作りました。
上で挙げなかった細かい内容も含まれているので、ぜひプレイしてみてください。