Start · Sprachen · JavaScript · Referenz · Object.is()

Object.is()

Methode

Die statische Methode <code>Object.is()</code> prüft ohne Typumwandlung, ob zwei Werte derselbe Wert sind, und unterscheidet dabei <code>+0</code>/<code>-0</code> und erkennt <code>NaN</code>.

seit JavaScript ES2015 Kategorie: method-property

Signatur

Object.is(value1, value2)

Beschreibung

Object.is() implementiert den Vergleichsalgorithmus SameValue aus der ECMAScript-Spezifikation. Zwei Werte gelten als gleich, wenn beide undefined, beide null, beide true bzw. beide false sind, wenn beide Strings mit denselben Zeichen in derselben Reihenfolge sind, wenn beide dasselbe Objekt referenzieren, wenn beide BigInts mit demselben Wert oder beide dasselbe Symbol sind. Bei Zahlen sind zwei Werte gleich, wenn beide +0, beide -0, beide NaN oder beide ungleich null, nicht NaN und vom Wert her gleich sind.

Anders als == wandelt Object.is() keine Typen um. "" == false ergibt also true, Object.is("", false) dagegen false. Von === unterscheidet sich die Methode nur in zwei Randfällen: Object.is(NaN, NaN) ergibt true (bei === ist das false), und Object.is(0, -0) ergibt false (bei === ist das true).

Nützlich ist die Methode vor allem dort, wo diese Randfälle wichtig sind: bei der Änderungserkennung in State-Management-Bibliotheken (React vergleicht zum Beispiel Hook-Abhängigkeiten und State mit Object.is), in Memoisierungs-Caches, in numerischen Algorithmen, in denen das Vorzeichen der Null zählt (z. B. 1 / -0 === -Infinity), und in Test-Frameworks (expect(x).toBe(y) in Jest).

Objekte werden nur nach Identität verglichen, nicht nach Inhalt. Zwei verschiedene Objekte mit gleichen Eigenschaften sind also nicht gleich. Für einen Vergleich nach Inhalt (Deep Equality) braucht man eine eigene Funktion oder eine Bibliothek.

Parameter

Name Typ Default Beschreibung
$value1 Pflicht any Der erste Wert des Vergleichs. Beliebiger Typ, einschließlich primitiver Werte, Objekte, Symbole und BigInts.
$value2 Pflicht any Der zweite Wert des Vergleichs. Wird ohne Typumwandlung mit value1 verglichen.

Rückgabewert

Typ
boolean
Beschreibung
true, wenn beide Werte nach dem SameValue-Algorithmus derselbe Wert sind, sonst false.

Beispiele

Grundlegende Vergleiche und Unterschiede zu ===

console.log(Object.is(25, 25));          // true
console.log(Object.is('foo', 'foo'));    // true
console.log(Object.is('foo', 'bar'));    // false
console.log(Object.is(null, undefined)); // false
console.log(Object.is('', false));       // false (keine Typumwandlung)

// Die beiden Randfälle, in denen es von === abweicht
console.log(NaN === NaN, Object.is(NaN, NaN)); // false true
console.log(0 === -0, Object.is(0, -0));       // true false
console.log(Object.is(-0, -0));                // true
console.log(Object.is(0n, -0n));               // true (bei BigInt gibt es kein -0)
true true false false false false true true false true true

Objekte werden nach Identität verglichen

const user = { name: 'Anna' };
const sameRef = user;
const copy = { ...user };

console.log(Object.is(user, sameRef)); // true – dieselbe Referenz
console.log(Object.is(user, copy));    // false – anderes Objekt, gleicher Inhalt

const sym = Symbol('id');
console.log(Object.is(sym, sym));                  // true
console.log(Object.is(Symbol('id'), Symbol('id'))); // false
true false true false

Änderungserkennung in einem einfachen Store

const createStore = (initial) => {
  let state = initial;
  const listeners = new Set();
  return {
    get: () => state,
    set: (next) => {
      // Nur bei echter Änderung benachrichtigen – NaN → NaN zählt nicht als Änderung
      if (Object.is(state, next)) return;
      state = next;
      listeners.forEach((fn) => fn(state));
    },
    subscribe: (fn) => (listeners.add(fn), () => listeners.delete(fn)),
  };
};

const store = createStore(NaN);
store.subscribe((v) => console.log('Neuer Wert:', v));
store.set(NaN); // keine Ausgabe
store.set(-0);  // Neuer Wert: -0
store.set(0);   // Neuer Wert: 0 (Vorzeichen hat sich geändert)
Neuer Wert: -0 Neuer Wert: 0

Negative Null erkennen

const isNegativeZero = (n) => Object.is(n, -0);

const temperatures = [0, -0, 3.5, -1 * 0];
console.log(temperatures.map(isNegativeZero));

// Math.round kann -0 liefern
console.log(isNegativeZero(Math.round(-0.4)));
[ false, true, false, true ] true

// Wichtig · Fallstricke

  • Kein Deep-Equal: Objekte, Arrays, Date- und Map-Instanzen werden nur nach Referenz verglichen. Object.is([], []) ergibt false.
  • Andere Algorithmen in der Sprache: Array.prototype.includes(), Map und Set verwenden SameValueZero: NaN gilt dort als gleich zu sich selbst, +0 und -0 aber ebenfalls als gleich. indexOf() verwendet dagegen === und findet NaN deshalb nie. Nur Object.is() unterscheidet +0 und -0.
  • Nicht als Standard-Vergleich verwenden: Im normalen Code ist === meist die richtige Wahl. Mit Object.is() kann eine -0 aus Berechnungen wie Math.round(-0.4) unerwartet zu false führen.
  • Nur ein Argument: Fehlt das zweite Argument, wird es als undefined behandelt. Object.is(undefined) ergibt also true.
  • Kompatibilität: Seit ES2015 in allen modernen Browsern und in Node.js verfügbar (Baseline), nicht im Internet Explorer. Ein Polyfill ist einfach: (x, y) => x === y ? x !== 0 || 1 / x === 1 / y : x !== x && y !== y.