Get to know MDN better
Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.
JavaScript bietet drei verschiedene Wertvergleichsoperationen:
Welche Operation Sie wählen, hängt davon ab, welche Art von Vergleich Sie durchführen möchten. Kurz gesagt:
Diese entsprechen drei von vier Gleichheitsalgorithmen in JavaScript:
Beachten Sie, dass die Unterschiede zwischen diesen sich auf den Umgang mit Primärtypen beziehen; keine von ihnen vergleicht, ob die Parameter strukturell ähnlich sind. Für nicht-primitive Objekte x und y, die die gleiche Struktur haben, aber unterschiedliche Objekte sind, werden alle oben genannten Formen zu false ausgewertet.
Strikte Gleichheit vergleicht zwei Werte auf Gleichheit. Keiner der Werte wird implizit in einen anderen Wert konvertiert, bevor der Vergleich erfolgt. Wenn die Werte unterschiedliche Typen haben, werden die Werte als ungleich angesehen. Wenn die Werte den gleichen Typ haben, keine Zahlen sind und den gleichen Wert haben, werden sie als gleich angesehen. Schließlich, wenn beide Werte Zahlen sind, werden sie als gleich angesehen, wenn beide nicht NaN sind und den gleichen Wert haben, oder wenn einer +0 und einer -0 ist.
Strikte Gleichheit ist fast immer die richtige Vergleichsoperation. Für alle Werte außer Zahlen verwendet sie die offensichtliche Semantik: Ein Wert ist nur sich selbst gleich. Für Zahlen verwendet sie leicht unterschiedliche Semantik, um zwei verschiedene Randfälle abzudecken. Der erste ist, dass Gleitkommazahlen entweder positiv oder negativ unterzeichnet sein können. Dies ist nützlich, um bestimmte mathematische Lösungen darzustellen, aber da die meisten Situationen keinen Unterschied zwischen +0 und -0 machen, behandelt die strikte Gleichheit sie als den gleichen Wert. Der zweite ist, dass Gleitkommazahlen das Konzept eines „nicht-zahl“-Werts (NaN) enthalten, um die Lösung bestimmter unbestimmter mathematischer Probleme darzustellen: negative Unendlichkeit addiert zu positiver Unendlichkeit, zum Beispiel. Strikte Gleichheit behandelt NaN als ungleich zu jedem anderen Wert — einschließlich sich selbst. (Der einzige Fall, in dem (x !== x) true ist, ist, wenn x NaN ist.)
Neben === wird strikte Gleichheit auch von Methoden zur Array-Indexsuche verwendet, einschließlich Array.prototype.indexOf(), Array.prototype.lastIndexOf(), TypedArray.prototype.indexOf(), TypedArray.prototype.lastIndexOf() und bei case-Vergleich. Das bedeutet, dass Sie indexOf(NaN) nicht verwenden können, um den Index eines NaN-Werts in einem Array zu finden, oder NaN als case-Wert in einer switch-Anweisung verwenden können, um es zu etwas zu machen, das übereinstimmt.
Lose Gleichheit ist symmetrisch: A == B hat immer identische Semantik wie B == A für beliebige Werte von A und B (außer für die Reihenfolge der angewandten Konvertierungen). Das Verhalten bei der Durchführung der losen Gleichheit mit == ist wie folgt:
Traditionell und gemäß ECMAScript sind alle Primitiven und Objekte lose ungleich zu undefined und null. Aber die meisten Browser erlauben einer sehr engen Klasse von Objekten (insbesondere das document.all-Objekt für jede Seite), in einigen Kontexten so zu agieren, als ob sie den Wert undefined emulieren. Lose Gleichheit ist ein solcher Kontext: null == A und undefined == A werten auf true aus, wenn und nur dann A ein Objekt ist, das undefined emuliert. In allen anderen Fällen ist ein Objekt niemals lose gleich undefined oder null.
In den meisten Fällen wird die Verwendung von loser Gleichheit nicht empfohlen. Das Ergebnis eines Vergleichs unter Verwendung strikter Gleichheit lässt sich leichter vorhersagen und kann aufgrund des Fehlens von Typkonversionen schneller ausgewertet werden.
Das folgende Beispiel demonstriert lose Gleichheitsvergleiche, die das Zahlen-Primitiv 0, das BigInt-Primitiv 0n, das String-Primitiv '0' und ein Objekt, dessen toString()-Wert '0' ist, umfassen.
Lose Gleichheit wird nur vom ==-Operator verwendet.
Gleichheit mit demselben Wert bestimmt, ob zwei Werte in allen Kontexten funktional identisch sind. (Dieser Anwendungsfall zeigt eine Instanz des Liskovschen Substitutionsprinzips.) Ein Beispiel tritt auf, wenn versucht wird, eine unveränderliche Eigenschaft zu ändern:
Object.defineProperty wirft eine Ausnahme, wenn versucht wird, eine unveränderliche Eigenschaft zu ändern, tut aber nichts, wenn keine tatsächliche Änderung angefordert wird. Wenn v -0 ist, wurde keine Änderung angefordert, und es wird kein Fehler ausgelöst. Intern wird der neu angegebene Wert beim Neudefinieren einer unveränderlichen Eigenschaft mit dem aktuellen Wert mithilfe der Gleichheit mit demselben Wert verglichen.
Gleichheit mit demselben Wert wird von der Object.is-Methode bereitgestellt. Sie wird fast überall in der Sprache verwendet, wo ein Wert von gleichwertiger Identität erwartet wird.
Ähnlich wie Gleichheit mit demselben Wert, aber +0 und -0 werden als gleich angesehen.
Gleichheit mit demselben Wert Null ist nicht als JavaScript-API verfügbar, kann jedoch mit benutzerdefiniertem Code implementiert werden:
Gleichheit mit demselben Wert Null unterscheidet sich von der strikten Gleichheit dadurch, dass NaN als gleichwertig angesehen wird, und von der Gleichheit mit demselben Wert dadurch, dass -0 als gleichwertig zu 0 angesehen wird. Dies führt dazu, dass es in der Regel das sinnvollste Verhalten während der Suche aufweist, besonders wenn mit NaN gearbeitet wird. Es wird von Array.prototype.includes(), TypedArray.prototype.includes() sowie von Methoden von Map und Set zur Prüfung der Schlüsselgleichheit verwendet.
Menschen vergleichen oft doppeltes und dreifaches Gleichheitszeichen, indem sie sagen, eines sei eine "erweiterte" Version des anderen. Zum Beispiel könnte man sagen, dass das doppelte Gleichheitszeichen eine erweiterte Version des dreifachen Gleichheitszeichens ist, da das erstere alles tut, was das letztere tut, aber mit Typkonvertierung auf seinen Operanden — zum Beispiel 6 == "6". Alternativ kann behauptet werden, dass das doppelte Gleichheitszeichen die Grundlinie ist und das dreifache Gleichheitszeichen eine Erweiterung darstellt, da es die beiden Operanden erfordert, denselben Typ zu haben, was eine zusätzliche Einschränkung darstellt.
Diese Denkweise impliziert jedoch, dass die Gleichheitsvergleiche ein eindimensionales "Spektrum" bilden, bei dem "völlig strikt" am einen Ende und "völlig lose" am anderen liegt. Dieses Modell versagt bei Object.is, da es weder "lockerer" als das doppelte Gleichheitszeichen noch "strikter" als das dreifache Gleichheitszeichen ist, noch dass es irgendwo dazwischen passt (d.h. sowohl strikter als das doppelte Gleichheitszeichen, aber lockerer als das dreifache Gleichheitszeichen). Wir können aus der Vergleichstabelle unten sehen, dass dies auf die Weise zurückzuführen ist, wie Object.is NaN behandelt. Beachten Sie, dass wenn Object.is(NaN, NaN) auf false ausgewertet würde, wir sagen könnten, dass es auf dem losen/strikten Spektrum als eine noch striktere Form des dreifachen Gleichheitszeichens passt, eine die zwischen -0 und +0 unterscheidet. Die NaN-Behandlung bedeutet jedoch, dass dies nicht wahr ist. Leider muss Object.is in Bezug auf seine spezifischen Merkmale betrachtet werden, anstatt in Bezug auf seine Laxheit oder Strenge gegenüber den Gleichheitsoperatoren.
| undefined | undefined | ✅ true | ✅ true | ✅ true | ✅ true |
| null | null | ✅ true | ✅ true | ✅ true | ✅ true |
| true | true | ✅ true | ✅ true | ✅ true | ✅ true |
| false | false | ✅ true | ✅ true | ✅ true | ✅ true |
| 'foo' | 'foo' | ✅ true | ✅ true | ✅ true | ✅ true |
| 0 | 0 | ✅ true | ✅ true | ✅ true | ✅ true |
| +0 | -0 | ✅ true | ✅ true | ❌ false | ✅ true |
| +0 | 0 | ✅ true | ✅ true | ✅ true | ✅ true |
| -0 | 0 | ✅ true | ✅ true | ❌ false | ✅ true |
| 0n | -0n | ✅ true | ✅ true | ✅ true | ✅ true |
| 0 | false | ✅ true | ❌ false | ❌ false | ❌ false |
| "" | false | ✅ true | ❌ false | ❌ false | ❌ false |
| "" | 0 | ✅ true | ❌ false | ❌ false | ❌ false |
| '0' | 0 | ✅ true | ❌ false | ❌ false | ❌ false |
| '17' | 17 | ✅ true | ❌ false | ❌ false | ❌ false |
| [1, 2] | '1,2' | ✅ true | ❌ false | ❌ false | ❌ false |
| new String('foo') | 'foo' | ✅ true | ❌ false | ❌ false | ❌ false |
| null | undefined | ✅ true | ❌ false | ❌ false | ❌ false |
| null | false | ❌ false | ❌ false | ❌ false | ❌ false |
| undefined | false | ❌ false | ❌ false | ❌ false | ❌ false |
| { foo: 'bar' } | { foo: 'bar' } | ❌ false | ❌ false | ❌ false | ❌ false |
| new String('foo') | new String('foo') | ❌ false | ❌ false | ❌ false | ❌ false |
| 0 | null | ❌ false | ❌ false | ❌ false | ❌ false |
| 0 | NaN | ❌ false | ❌ false | ❌ false | ❌ false |
| 'foo' | NaN | ❌ false | ❌ false | ❌ false | ❌ false |
| NaN | NaN | ❌ false | ❌ false | ✅ true | ✅ true |
Im Allgemeinen ist die einzige Zeit, in der Object.is's spezielles Verhalten gegenüber Nullen von Interesse sein könnte, bei der Verfolgung bestimmter Metaprogrammierungsschemata, insbesondere im Hinblick auf Eigenschaftsbeschreibungen, wenn es wünschenswert ist, dass Ihre Arbeit einige der Eigenschaften von Object.defineProperty spiegelt. Wenn Ihr Anwendungsfall dies nicht erfordert, wird vorgeschlagen, Object.is zu vermeiden und stattdessen === zu verwenden. Auch wenn Ihre Anforderungen den Vergleich zwischen zwei NaN-Werten erfordern, die zu true auswerten, ist es im Allgemeinen einfacher, die NaN-Prüfungen (unter Verwendung der isNaN-Methode aus früheren Versionen von ECMAScript) spezifisch zu behandeln, als herauszufinden, wie umliegende Berechnungen das Vorzeichen von Nullen, die Sie in Ihrem Vergleich antreffen, beeinflussen könnten.
Hier ist eine nicht erschöpfende Liste von eingebauten Methoden und Operatoren, die dazu führen könnten, dass sich eine Unterscheidung zwischen -0 und +0 in Ihrem Code manifestiert:
- (Unäres Negieren)Betrachten Sie das folgende Beispiel:
Wenn obj.velocity 0 (oder zu 0 berechnet wird) ist, wird an dieser Stelle ein -0 eingeführt und breitet sich in stoppingForce aus.
Math.atan2, Math.ceil, Math.pow, Math.roundIn einigen Fällen ist es möglich, dass ein -0 in einen Ausdruck als Rückgabewert dieser Methoden eingeführt wird, auch wenn kein -0 als einer der Parameter vorhanden ist. Zum Beispiel wird Math.pow() verwendet, um -Infinity auf eine beliebige negativen ungerade Exponenten zu erheben, wertet zu -0. Konsultieren Sie die Dokumentation für die einzelnen Methoden.
Math.floor, Math.max, Math.min, Math.sin, Math.sqrt, Math.tanEs ist möglich, -0 als Rückgabewert aus diesen Methoden in einigen Fällen zu erhalten, bei denen ein -0 als einer der Parameter existiert. Z.B. Math.min(-0, +0) wertet zu -0 aus. Konsultieren Sie die Dokumentation für die einzelnen Methoden.
~, <<, >>Jeder dieser Operatoren verwendet intern den ToInt32-Algorithmus. Da es in der internen 32-Bit-Integer-Implementierung nur eine Darstellung für 0 gibt, überlebt -0 nicht eine Rundreise nach einer inversen Operation. Z.B. Object.is(~~(-0), -0) und Object.is(-0 << 2 >> 2, -0) werten beide zu false aus.
Sich auf Object.is zu verlassen, wenn das Vorzeichen von Nullen nicht berücksichtigt wird, kann gefährlich sein. Natürlich erfüllt es genau die gewünschte Funktion, wenn die Absicht darin besteht, zwischen -0 und +0 zu unterscheiden.
Die Object.is-Spezifikation behandelt alle Instanzen von NaN als dasselbe Objekt. Seit Typed Arrays jedoch verfügbar sind, können wir unterschiedliche Gleitkommadarstellungen von NaN haben, die sich nicht in allen Kontexten identisch verhalten. Zum Beispiel:
Der Bauplan für ein besseres Internet.
Besuche die gemeinnützige Muttergesellschaft der Mozilla Corporation, die Mozilla Foundation.
Teile dieses Inhalts sind ©1998–2026 von einzelnen mozilla.org-Mitwirkenden. Inhalte sind verfügbar unter einer Creative-Commons-Lizenz.