JavaScriptの==と===の違い|"0"==falseはtrue、0==nullはfalseになる
JavaScriptの==は、型が違うと変換してから比べる。===は型が違えばfalse。
==が裏でやっている変換の順番と、フォームの値を比べるときの取り違えをMDNの説明で整理した。
JavaScriptの == と === の違いは、比べる前に型をそろえるかどうか、の一点だ。== は型が違うと片方を変換してから比べるので、"0" == false も null == undefined も true になる。=== は型が違った時点で false を返す。
この記事では、MDN の説明をもとに、== が裏でやっている変換の順番と、フォームの値を比べるときに起きやすい取り違えを整理する。
仕様の説明は、どれも MDN に書いてあることだ。
「僕は〜と思う」と書いたところだけが、僕の意見になる。
まず結果だけ並べてみる
MDN の例から、== で true になる組み合わせを抜き出すと、こうなる。
"1" == 1; // true
0 == false; // true
null == undefined; // true
0 == null; // false
[1, 2, 3] == "1,2,3"; // true
"1" === 1; // false
0 === false; // false
null === undefined; // false上の段が ==、下の段が同じ組み合わせを === で比べたものだ。
同じ値どうしなのに、演算子を1文字変えただけで答えが逆になる。0 == null だけが false なのも、ぱっと見では理由が分からない。
==が裏でやっている変換の順番
MDN は、== の動きをおおまかに次の順で説明している。
上から順に当てはめて、当てはまったところで答えが決まる。
1. 型が同じなら、そのまま比べる
数値どうし、文字列どうしなら、変換はしない。
この段階では === と同じ動きになる。
ただし NaN はどちらの演算子でも、自分自身とも一致しない。
2. 片方がnullかundefinedなら、もう片方もnullかundefinedのときだけtrue
null == undefined が true になるのは、この決まりのせいだ。
そして 0 == null が false になるのも、同じ決まりのせいだ。null は数値に変換されずに、ここで判定が終わる。
3. 片方がオブジェクトなら、プリミティブに変換する
配列もオブジェクトなので、文字列と比べると先に文字列へ変換される。[1, 2, 3] は "1,2,3" になるので、[1, 2, 3] == "1,2,3" は true になる。
逆に、オブジェクトどうしは中身ではなく「同じものを指しているか」で比べるので、中身が同じ配列を2つ作って == で比べても false になる。
4. 真偽値は数値に、文字列は数値に直してから比べる
最後の段で、真偽値は true が1、false が0に変換される。
数値と文字列なら、文字列のほうが数値に変換される。"0" == false は、false が0になり、"0" も0になるので true になる。
数値にできない文字列は NaN になり、NaN は何とも一致しないので false になる。
MDN は、=== は実質この1番だけを行って、それ以外は全部 false を返す、と説明している。
覚える量の差は、ここにある。
フォームの値を比べるときに起きる取り違え
この違いがいちばん効いてくるのは、入力欄の値を比べるときだと思う。input 要素の value は、type="number" の欄でも文字列で返ってくる。
// 数量の欄に 0 と入力されたとする
const qty = document.querySelector("#qty").value; // "0"(文字列)
qty === 0; // false(型が違う)
qty == 0; // true("0" を数値に直してから比べる)
qty == false; // true=== に書き換えただけだと、今まで通っていた判定が急に通らなくなる。
かといって == のままだと、空欄の "" も 0 == "" で true になり、「0と入力された」と「何も入力されていない」の区別がつかない。
僕は、比べる前に自分で型をそろえてから === で比べるのがいちばん読みやすいと思う。
数値の欄なら、MDN にある valueAsNumber を使うと、最初から数値で受け取れる。
数値にできないときは NaN が返るので、空欄はそこで弾ける。
const qty = document.querySelector("#qty").valueAsNumber;
if (Number.isNaN(qty)) {
// 空欄、または数値にできない入力
} else if (qty === 0) {
// 0 と入力された
}NaN を === で判定できない話は、NaNが自分自身と一致しない記事に書いた。
文字列のまま数値を扱って起きる別の取り違えは、並び替えで100が2より先に来た記事にある。
==をあえて使う場面はあるか
MDN の説明どおりなら、x == null は x が null か undefined のときだけ true になる。
2つまとめて判定したいときに、この書き方を使うコードはよく見かける。
ただ、僕は x === null || x === undefined と書くか、?? のような専用の書き方に寄せるほうが好きだ。
読む人が == の変換の順番を思い出さなくて済むからだ。
チームで書くなら、どちらに寄せるかを決めておくのがいちばん効くと思う。
まとめ
==は型が違うと変換してから比べる。===は型が違えばfalsenullとundefinedは==でお互いにだけ一致し、0や""とは一致しない- 真偽値は1と0に、文字列は数値に直してから比べられる。だから
"0" == falseはtrue - 入力欄の
valueは文字列。valueAsNumberなどで型をそろえてから===で比べる
出典
ほかにも書いています
受託・note・スタンプこういう仕組みを作る相談を受けています
毎日の更新・データ集め・集計の自動化/3万円〜収益がいくらだったか、どの施策が外れたか
note / 個人の視点で掘り下げていますスタンプラリーに挑戦する
行った場所は、現地チェックインで記録に残せます※受託の相談とnoteは、運営者が個人で受けている・書いているものです。
