結論
=== は見た目が同じでも、言語によって比較対象が違う。
- JavaScript:型 + 値の厳密比較
-
Kotlin:参照の同一性(同じオブジェクトか)
この違いを知らないと、レビューやデバッグで確実に混乱する。
JavaScript:=== は「型と値」を比較する
JavaScriptでは === は厳密等価演算子。
型変換を行わず、「型」と「値」の両方を比較する。
1 === 1 // true
1 === "1" // false
null === undefined // false
オブジェクトの場合
オブジェクトは参照が比較される。
const a = { x: 1 }
const b = { x: 1 }
const c = a
a === b // false
a === c // true
- プリミティブ:値 + 型
- オブジェクト:参照
という二段構えになっている点が重要。
Kotlin:=== は「参照の同一性」を比較する
Kotlinの === はreferential equality。
同じインスタンスかどうかのみを比較する。
val a = String("abc".toCharArray())
val b = String("abc".toCharArray())
a === b // false
値が同じでも、インスタンスが違えば false。
val c = a
a === c // true
Kotlin:== は「値の等価性」を比較する
Kotlinで値を比較したい場合は == を使う。
内部的には equals() が呼ばれる。
val a = String("abc".toCharArray())
val b = String("abc".toCharArray())
a == b // true
データクラスでは特に重要。
data class User(val id: Int)
val u1 = User(1)
val u2 = User(1)
u1 == u2 // true
u1 === u2 // false
他言語との比較
| 言語 | 演算子 | 比較内容 |
|---|---|---|
| JavaScript | === |
型 + 値(objectは参照) |
| Kotlin | === |
参照の同一性 |
| Kotlin | == |
値の等価(equals) |
| Java | == |
プリミティブは値 / オブジェクトは参照 |
| Swift | === |
クラスの参照比較 |
| Python |
== / is
|
値 / 参照 |
※ Swift や Python は「役割が分離されている」点で Kotlin に近い。
よくあるハマりどころ
1. 「JSの === 感覚」で Kotlin を書く
if (a === b) { ... } // 値比較のつもり → バグ
→ 値比較は ==
2. レビューで === を見て意図が読めない
Kotlinで === が出てきたら、
- キャッシュ
- シングルトン
- 同一インスタンス保証
を疑うべき。
3. 言語横断で認知がズレる
「=== = 厳密比較」という感覚はJavaScript限定。
まとめ
- 記号ではなく仕様を見る
- Kotlinで値比較は
== -
===は「参照が重要な場面」でのみ使う
=== を見たら、「何を比較しているのか」を必ず言語仕様で確認するのが安全。
追記(JavaScript の === の厳密仕様について)
本記事では言語間比較を主目的としているため、
JavaScript の === については
型 + 値の厳密比較
という実務上の理解に寄せた表現をしています。
厳密には、=== は ECMAScript の Strict Equality Comparison に従い、
Number 型には以下の特殊ケースがあります。
const v1 = +0
const v2 = -0
console.log(v1 === v2) // true
console.log(Object.is(v1, v2)) // false
const v1 = NaN
const v2 = NaN
console.log(v1 === v2) // false
console.log(Object.is(v1, v2)) // true
-
+0と-0は===では同値扱いになる -
NaNは===では自分自身とも等しくならない -
Object.is()は SameValue 比較であり挙動が異なる
今回は Kotlin との比較軸を揃えるため、
詳細仕様までは踏み込みませんでしたが、
正確性の観点から補足として追記しました。