Menu
日本語

JavaScriptの等価演算子 == と === の違いとObject.is

JavaScriptの等価比較を整理。厳密等価 === とゆるい等価 == の挙動の違い、NaNやオブジェクト比較のクセ、Object.isを使うべき場面まで実例でまとめます。

「これって等しい?」を確かめる2つの方法

JavaScriptには等価演算子が2種類あります。===(厳密等価)と ==(緩い等価)です。見た目はほぼ同じなのに、動きはまるで別物です。

index.js
Output
Click Run to see the output here.

=== は「型も値も同じか」をチェックする演算子です。一方の == は、先に両辺を共通の型に変換してから比較します。この型変換(type coercion)こそが、JavaScript の等価比較が長年ややこしいと言われてきた元凶です。

結論から言えば、基本は === を使えば OK。とはいえ、「何を避けているのか」を一度はちゃんと理解しておく価値があります。

厳密等価(===):まずはこれを使う

=== は、型と値のどちらも一致したときだけ true を返します。型変換は一切行われないので、思わぬ挙動に悩まされることもありません。

index.js
Output
Click Run to see the output here.

型が違えば、その時点で即 false になります。型が同じなら、JavaScript は値そのものを比較します。プリミティブなら値の比較、オブジェクトなら参照の比較です(これについては後ほど)。

!== は厳密不等価演算子で、同じルールを逆にした挙動になります。

等価演算子 == の裏にある暗黙の型変換

== は左右の型が違っていても使えます。ただし比較する前に、両辺の型を揃えようとして型変換(coercion)が裏で走ります。

index.js
Output
Click Run to see the output here.

厳密なルールは仕様書に書かれていて、読めばそこまでひどくはないのですが、デバッグ中にパッと思い出せるかというと話は別です。"0" == falsetrue になるのは、ベテランの開発者でも引っかかる罠です。[] == false も同様に true になります(配列が "" に変換され、さらに 0 に変換されるため)。

こうした背景から、多くのスタイルガイドや ESLint の eqeqeq ルールでは、デフォルトで === を使うことが推奨されています。1文字多くタイプする代わりに、頭で覚えておけるルールだけで済むわけです。

== が役に立つ唯一のパターン

等価演算子の中で、覚えておく価値があるイディオムが1つだけあります。x == null は、xnull または undefined のときに true を返し、それ以外はすべて false になります。

index.js
Output
Click Run to see the output here.

厳密に書くなら x === null || x === undefined になりますが、どうしても冗長に見えてしまいます。そこで == null だけは例外としてOKにしているコードベースも少なくありません。どちらの方針を採るにせよ、プロジェクト内で統一するのが大事です。

オブジェクトは参照で比較される

オブジェクト・配列・関数を比較するとき、===== も聞いていることは同じで、「両辺が同じメモリ上のオブジェクトを指しているか?」です。決して「中身が同じか?」を見ているわけではありません。

index.js
Output
Click Run to see the output here.

中身がまったく同じオブジェクトリテラルでも、別物として扱われます。これは誰もが一度はハマるポイントです。

値ベースで比較したいときは、自前でヘルパー関数を書くか、ライブラリ(lodash.isequal)を使うか、あるいはシンプルなプレーンオブジェクトなら JSON.stringify でシリアライズして比べる方法があります。

index.js
Output
Click Run to see the output here.

JSON.stringify が効くのは単純なデータだけです。関数、undefined、シンボルは無視されますし、形によってはエンジン間でキーの順序も保証されません。サッと確認する用途には使えますが、汎用的な解決策にはなりません。

NaN はどんな値とも等しくならない

NaN(not a number)は、数値演算で意味のある答えが出せないときに JavaScript が返す値です。たとえば 0/0Number("abc")Math.sqrt(-1) などですね。等価演算子は ===== も、どちらか一方が NaN なら false を返します。両辺とも NaN の場合でも同じです。

index.js
Output
Click Run to see the output here.

NaN を判定したいときは Number.isNaN(value) を使いましょう。昔ながらのグローバル関数 isNaN は引数を先に型変換してしまうので、isNaN("hello")true を返します。これはまず期待した挙動ではないはずです。

Object.is:ほぼ ===、ただし2つだけ違う

Object.is(a, b) は基本的に === と同じように動きますが、次の2つのケースだけ挙動が異なります。

index.js
Output
Click Run to see the output here.

ほとんどのケースで使うべきは === です。Object.is の出番は、NaN を自分自身と等しいものとして扱いたい場合や、+0-0 を区別したい場合に限られます。どちらもまれなケースですが、数値計算やフレームワークの内部実装では意外と重要になることもあります(実際、Reactは状態の比較に Object.is を使っています)。

不等価演算子も同じ使い分け

!== は厳密、!= はゆるい比較で、こちらも同じ方針が当てはまります。

index.js
Output
Click Run to see the output here.

迷ったら !== を基本にしましょう。== null を許可しているプロジェクトなら、その裏返しである「null でも undefined でもない」を判定する != null も合わせて許可して構いません。

値を比較するときのチェックリスト

2つの値を比較したくなったら、次の順で考えてみてください。

  • プリミティブ同士で、型も揃っているはず?=== を使う。
  • null や undefined の判定? → スタイルガイドが許すなら x == null でOK。ダメなら x === null || x === undefined
  • NaN の判定?Number.isNaN(x)
  • オブジェクトを参照(同一性)で比較したい?=== がまさにそれ。
  • オブジェクトを中身で比較したい? → 自前のヘルパーを書くか、ライブラリを使うか、シリアライズして比べる。標準の演算子ではどうにもなりません。

基本は ===== は「== null のときだけ使う特別な道具」と割り切る。これだけで、JavaScript の FAQ によく並ぶ等価比較の落とし穴はほとんど避けられます。

次は演算子の話

厳密等価は、JavaScript に用意されている演算子のほんの一部にすぎません。次のドキュメントでは、算術・論理・代入をはじめ、日々のコーディングで頼りになる省略形の演算子まで、残りをまとめて見ていきます。

よくある質問

JavaScriptの == と === は何が違う?

=== は厳密等価で、型と値の両方が一致したときだけ true を返します。一方の == はゆるい等価で、比較前に型変換(暗黙の型強制)を行います。たとえば 1 === '1'false ですが、1 == '1' は文字列が数値に変換されるため true になります。

JavaScriptでは常に === を使うべき?

基本的にはイエスです。=== はルールがシンプルで挙動を予測しやすいので、デフォルトで使うのが無難。例外としてよく使われるのが x == null で、これは nullundefined の両方に一発でマッチします。ESLintの eqeqeq ルールでも、このパターンだけはオプションで許可できるようになっています。

なぜ NaN === NaN は false になるの?

IEEE 754仕様で「NaN はどんな値とも等しくない(自分自身とも)」と決められているためです。そのため NaN が絡むとどの等価演算子も false を返します。値が NaN かを判定したいときは Number.isNaN(x) を使うか、Object.is(NaN, NaN) であれば true が返ります。

JavaScriptでオブジェクト同士を比較するには?

===== もオブジェクトは「参照」で比較します。中身ではありません。なので {a: 1} === {a: 1} は別インスタンスなので false です。値として比較したい場合は自前で比較関数を書くか、Lodashの isEqual のようなライブラリを使うか、単純なプレーンオブジェクトなら JSON.stringify で文字列化して比較するのが手軽です。

Coddyでコードを学ぼう

始める