厳密等価演算子(===)と等価演算子(==)の違い ― JavaScript で == を使わない方がいい理由
結論
JavaScript で値を比較するときは、=== を使う。== は型が違う値を比較する際に「型強制」を行うため、直感に反する結果になりやすい。実プロジェクトでは ESLint の eqeqeq ルールで == を禁止しているケースが多い。
0 == "" // true("" は 0 に変換される)
0 == "0" // true("0" は 0 に変換される)
0 == false // true(false は 0 に変換される)
"" == false // true
[] == false // true([] は "" に変換され、さらに 0 に)
null == undefined // true(特別ルール)
"1" == true // true(true は 1、"1" も 1)
0 === "" // false
0 === "0" // false
0 === false // false
[] === false // false
null === undefined // false
"1" === true // false
== は仕様の中に「型変換のルール」が10行以上ある複雑な演算子。覚えるより、=== を使う方が安全。
=== と == の違いを一行で
===(厳密等価): 型も値も完全に一致したときだけtrue==(等価): 型が違ったら片方を変換してから比較。値が一致したらtrue
// 型が同じなら === と == は同じ結果
1 === 1 // true
1 == 1 // true
"a" === "a" // true
"a" == "a" // true
// 型が違うと結果が分かれる
1 === "1" // false(型が違うので即 false)
1 == "1" // true("1" を 1 に変換してから比較)
型強制で起こる典型的な落とし穴
1. 空文字と 0 が等しい
"" == 0 // true
"" == false // true
0 == false // true
0 == "0" // true
"" == "0" // false ← これは仕様の例外
最後の "" == "0" は 両方が文字列のため型変換が起きず、単純な文字列比較で false になる。型が違うと変換するが、同じ型なら変換しない、というのが == のルール。同じ "0っぽい" 値同士でも結果が変わる。
2. null と undefined だけは特別扱い
null == undefined // true(特別ルール)
null == null // true
undefined == undefined // true
null == 0 // false
null == false // false
null == "" // false
undefined == 0 // false
undefined == false // false
null と undefined は 互いにだけ等しい。0 や false とは等しくない。これは ECMAScript 仕様で明示的に決められたルール。
3. 配列・オブジェクトとの比較
[] == false // true([] → "" → 0、false → 0)
[0] == false // true([0] → "0" → 0)
[] == 0 // true
[] == "" // true
[1] == 1 // true([1] → "1" → 1)
[1, 2] == "1,2" // true(配列の toString は "1,2")
{} == false // false({} は "[object Object]" になる)
オブジェクトと比較するとき、== は valueOf() または toString() を呼んでプリミティブに変換する。配列の toString() はカンマ区切り文字列を返すので、[1] == 1 が成立してしまう。
どんな時でも === で問題ないか
ほぼ全ての場面で === を使うべき。例外として意図的に null と undefined を同じものとして扱いたいケースがあるが、その場合も明示的に書く方が読みやすい。
// NG: 意図が不明
if (value == null) { /* null か undefined */ }
// OK: 意図が明示的
if (value === null || value === undefined) { /* null か undefined */ }
// 最近は Nullish 演算子で簡潔に
const x = value ?? defaultValue // value が null/undefined なら defaultValue
ESLint で == を禁止する
実プロジェクトでは eqeqeq ルールを設定して == を禁止するのが普通。
{
"rules": {
"eqeqeq": ["error", "always"]
}
}
"always" は例外なし全面禁止。"smart" にすると null との比較だけは例外扱いになる(x == null で null と undefined を両方判定)。コードベースの方針による。
TypeScript 環境なら @typescript-eslint/eqeqeq でも同じことができる。
TypeScript ではほぼ無関係?
TypeScript では型が一致しない値同士の == 比較がコンパイルエラーになるため、== で型強制に頼ろうとするとそもそもビルドが通らない。TypeScript なら === 一択。
const x: string = "1"
const y: number = 1
x == y // TS Error: This comparison appears to be unintentional
x === y // TS Error: 同じく
ただし、unknown や any 型と比較する場合は型チェックを抜けるため、TypeScript でも eqeqeq ルールを併用しておくと安全。
まとめ
===は型と値の両方を比較。ほぼ全てのケースで === を使う==は型が違うと片方を変換するため、空文字 == 0、null == undefined のような直感に反する結果が出る- 配列やオブジェクトとの
==比較は特に予測不能([] == falseが true) - ESLint の
eqeqeqルールで==を全面禁止しておくと安全 - TypeScript では型不一致の
==がコンパイルエラーになるため、自然に===を使うことになる