JavaScript

JavaScriptのObject.is():NaNと符号付きゼロを区別して値を比較する

この記事でわかること

Object.is()の引数・戻り値と、厳密等価演算子との違いを解説。NaNや符号付きゼロの比較、変更検知の活用例、ブラウザーとNode.jsでの実行手順、参照比較の注意点を学びます。

目的:何を「同じ値」と扱うかを明確にする

計算結果を前回の値と比較し、変化した場合だけ処理したいことがあります。このとき、数値には少し特殊なケースがあります。NaN === NaNはfalseになり、0 === -0はtrueになります。

Object.is()は、NaN同士を同じ値と扱い、正のゼロと負のゼロを区別する比較関数です。計算結果の状態管理や、ゼロの符号まで確かめたい確認処理に使えます。型の自動変換は行いません。

通常の比較をすべて置き換える必要はありません。扱うデータについて「計算不能という状態が続いたら同じと見なすか」「ゼロの符号に意味があるか」を決め、そのルールに合う場合に選びます。

動作環境と対応状況

2026年9月26日時点で確認したMDNでは、Object.is()は広く利用できる機能とされ、2015年9月から主要ブラウザー間で利用可能と説明されています。現行のChrome、Edge、Firefox、Safariで使えます。古いブラウザーや組み込み環境まで含めて無条件に対応するという意味ではありません。MDNの仕様・対応状況

Node.jsでも利用できます。本記事の実行対象はNode.js 22系とします。これは記事の環境指定であり、初めて対応したバージョンではありません。Node.js 22.0.0の公式資料でも、標準の検証機能がObject.is()による比較を使うことを確認できます。Node.js 22.0.0の比較仕様

サンプルは標準JavaScriptだけで構成し、DOM、外部ライブラリー、通信を使いません。同じJavaScriptコードをブラウザーとNode.jsの両方で実行できます。

引数・戻り値と比較ルール

呼び出し方はObject.is(value1, value2)です。インスタンスを作らず、Objectに直接指定して呼ぶ静的メソッドです。

  • 第1引数のvalue1は、比較する一方の値です。
  • 第2引数のvalue2は、比較するもう一方の値です。
  • 戻り値は真偽値で、同じ値ならtrue、異なる値ならfalseです。

数値以外も渡せます。文字列なら内容と順序を比較し、オブジェクトなら同じオブジェクトを参照しているかを比較します。比較対象を変更する処理はありません。

厳密等価演算子との違い

===との違いは、NaNと符号付きゼロの扱いです。文字列の"12"と数値の12は、どちらの比較方法でも異なる値になります。Object.is()の比較規則はSameValueと呼ばれます。MDNの等価性の解説

次の例では、比較結果を文字列として出力します。各コード例は外側をブロックで囲んでいるため、コンソールで繰り返し実行しても変数名が衝突しにくい構成です。

JavaScript
{
  const original = { count: 1 };
  const alias = original;

  console.log(`same number: ${Object.is(12, 12)}`);
  console.log(`different types: ${Object.is("12", 12)}`);
  console.log(`NaN with ===: ${NaN === NaN}`);
  console.log(`NaN with Object.is: ${Object.is(NaN, NaN)}`);
  console.log(`zero with ===: ${0 === -0}`);
  console.log(`zero with Object.is: ${Object.is(0, -0)}`);
  console.log(`same reference: ${Object.is(original, alias)}`);
  console.log(`new object: ${Object.is(original, { count: 1 })}`);
}

期待出力は次のとおりです。

CODE
same number: true
different types: false
NaN with ===: false
NaN with Object.is: true
zero with ===: true
zero with Object.is: false
same reference: true
new object: false

ブラウザーとNode.jsで実行する

ブラウザーの場合

Chromeなどで新しい空白タブを開き、開発者ツールのConsoleを選びます。上のJavaScriptコード全体を入力して実行すると、8行の結果が表示されます。複数行入力の実行キーは開発者ツールによって異なります。

コンソールには、最後の式の評価結果として追加のundefinedが表示されることがあります。これはサンプルが出力した8行とは別の表示です。貼り付けが制限される場合は、ブラウザーの案内を確認し、内容を理解したコードだけを入力してください。

Node.jsの場合

Node.js 22系がインストールされた環境で、上のコードをテキストエディターに貼り付け、object-is-demo.jsとして保存します。ターミナルで保存先のフォルダーを開き、次を実行してください。

Shell
node --version
node object-is-demo.js

最初のコマンドはバージョンを表示し、次のコマンドはサンプルの8行を出力します。追加パッケージのインストールは不要です。ファイル名をnodeコマンドに渡す実行方法は、Node.js公式の実行ガイドでも説明されています。

以降のJavaScript例も同じ手順で実行できます。Node.jsではファイルの内容を各例に置き換えて保存してください。本記事の期待出力は仕様とコードを照合したもので、実機実行による検証結果ではありません。

活用例:計算結果が変わったときだけ記録する

計算処理から同じ数値が連続して届く場合、変化したときだけ履歴を残すと記録量を減らせます。ここでは、NaNが続く場合も同じ状態と扱い、ゼロの符号が変われば記録する方針にします。

JavaScript
{
  const samples = [5, 5, NaN, NaN, 0, -0, -0, 8];
  let hasPrevious = false;
  let previous;

  function formatValue(value) {
    return Object.is(value, -0) ? "-0" : String(value);
  }

  for (const current of samples) {
    if (!hasPrevious || !Object.is(previous, current)) {
      console.log(`record: ${formatValue(current)}`);
      previous = current;
      hasPrevious = true;
    }
  }
}

期待出力は次のとおりです。

CODE
record: 5
record: NaN
record: 0
record: -0
record: 8

hasPreviousは、まだ一度も記録していない状態を表します。初期値として選んだ値と最初の入力が偶然一致しても、初回の記録を省略しないための変数です。

表示用のformatValue()でもObject.is()を使っています。通常の文字列化では負のゼロも"0"になるため、比較で区別できても出力から違いが見えなくなるからです。

この例は数値の状態変化を扱うためのものです。NaNの発生回数自体を障害分析に使う場合は、重複を省略せず別途数える必要があります。省略してよい情報を決めてから導入してください。

失敗例と制約

オブジェクトの内容までは比較しない

名前にObjectが含まれていても、プロパティを再帰的に調べる関数ではありません。同じ内容で作った別オブジェクトは異なると判定されます。また、同じオブジェクトを書き換えても参照自体は変わりません。

JavaScript
{
  const state = { count: 1 };
  const previous = state;

  state.count = 2;

  console.log(`reference unchanged: ${Object.is(previous, state)}`);
  console.log(`previous count: ${previous.count}`);
  console.log(`separate objects: ${Object.is({ count: 2 }, { count: 2 })}`);
}

期待出力は次のとおりです。

CODE
reference unchanged: true
previous count: 2
separate objects: false

previousへの代入は過去の内容の保存にはなりません。変更検知に使うなら、変更前の数値を別に保持するか、オブジェクトを直接変更せず新しい参照へ置き換える設計が必要です。内容の等しさが必要なら、比較対象のプロパティと比較規則を明示します。

小数の誤差や入力の正しさは判定しない

Object.is(0.1 + 0.2, 0.3)はfalseです。計算結果に含まれる浮動小数点の誤差を吸収する機能はありません。測定値などを比較するなら、用途に応じた許容誤差を別に設計してください。

また、2つの値が同じと判定されても、業務上有効な値とは限りません。今回の例でNaNを同じ状態として扱うことと、その値を保存・表示してよいかの判断は別です。

同期処理と例外の扱い

Object.is()は同期的に真偽値を返します。Promiseを返さないため、awaitや非同期の後始末は不要です。通常の値を比較するだけなら、比較用のtry...catchも必要ありません。

ただし、引数として渡す式は呼び出し前に評価されます。その式が例外を投げれば、比較まで到達しません。また、未対応環境で未定義のメソッドを呼べばエラーになります。古い実行環境を扱う際は、typeof Object.is === "function"で存在を確認し、利用できなければ環境の更新や互換実装を検討します。

公式参考資料

仕様の再確認にはMDNのObject.is()リファレンス、比較規則の選択にはMDNの等価性ガイドが役立ちます。

Node.js側の利用例はNode.js 22.0.0のAssert資料、保存したコードの実行手順はNode.jsのコマンドライン実行ガイドで確認できます。

PREFERRED SOURCES

Googleの優先するニュース提供元にSEの部屋を追加

Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。

Googleの設定画面で確認する 新しいタブで開きます

候補にSEの部屋が表示されない場合は、まだ追加できません。

y.
WRITTEN BY

y_ymo10

SEの部屋で、HTML・CSSからJavaScript・React・Next.jsまで、Web制作の開発ノートを公開しています。

ほかの開発ノートを読む →