Warum tut [NaN].includes(NaN) in JavaScript wahr zurückgeben?

Lesezeit: 7 Minuten

Benutzer-Avatar
Yossi Vainshtein

Ich bin vertraut mit NaN in JavaScript “seltsam” sein, d. h. NaN === NaN kehrt immer zurück false, wie hier beschrieben. So sollte man das nicht machen === Vergleiche zu überprüfen NaNaber verwenden Sie stattdessen isNaN(..).

Also war ich überrascht, das zu entdecken

> [NaN].includes(NaN)
true

Dies erscheint widersprüchlich. Warum dieses Verhalten?

Wie funktioniert es überhaupt? Tut das includes Methode speziell prüfen isNaN?

  • Sie möchten diesen Beitrag lesen github.com/tc39/proposal-Array.prototype.includes/issues/29

    – gnujoow

    22. März 2021 um 9:36 Uhr


  • This seems inconsistent, Ja, es scheint seltsam. NaN ist mit nichts gleich, einschließlich NaN, abgesehen von X. Aber ich nehme an, es wird hier gewählt, denn wenn es nicht wahr zurückgeben würde, wäre es sinnlos, NaN im Array zu haben, da es nie gefunden würde.

    – Keith

    22. März 2021 um 9:57 Uhr

  • @Keith es kann mit gefunden werden .some(). Es ist nur ein bisschen seltsam, dass Dies Methode wurde beschlossen, tatsächlich damit zu arbeiten NaN das ist im Grunde anders als alles andere. Abgesehen von Karte und Set. Für diejenigen, es tut sinnvoll behandeln NaN als den gleichen Wert, sonst werden die Datenstrukturen sehr unbrauchbar.

    – VLAZ

    22. März 2021 um 10:37 Uhr

Benutzer-Avatar
Nguyễn Van Phong

Entsprechend Dokument von MDN Sag das

Hinweis: Technisch gesehen, includes() nutzt die sameValueZero

Algorithmus, um festzustellen, ob das angegebene Element gefunden wird.

const x = NaN, y = NaN;
console.log(x == y); // false                -> using ‘loose’ equality
console.log(x === y); // false               -> using ‘strict’ equality
console.log([x].indexOf(y)); // -1 (false)   -> using ‘strict’ equality
console.log(Object.is(x, y)); // true        -> using ‘Same-value’ equality
console.log([x].includes(y)); // true        -> using ‘Same-value-zero’ equality

Genauere Erklärung:

  1. Gleichwertig-Null-Gleichheit ähnlich zu gleichwertige Gleichheit, aber +0 und –0 werden als gleich betrachtet.
  2. Gleichwertige Gleichheit wird bereitgestellt von der Objekt.is() Methode: Der einzige Unterschied zwischen Object.is() und === ist in ihre Behandlung von vorzeichenbehafteten Nullen und NaNs.

Geben Sie hier die Bildbeschreibung ein


Zusätzliche Ressourcen:

  • Welcher Gleichheitsoperator (== vs. ===) sollte in JavaScript-Vergleichen verwendet werden?
  • Array.prototype.includes vs. Array.prototype.indexOf
  • Sind +0 und -0 gleich?

  • Ich habe gerade hinzugefügt additional resources & Re-arrange sample code to make it clearer as well as more understandable. Wie wir vielleicht kennen lose & strict equality comparison, aber ich möchte sie alle auflisten, um uns zu helfen, einen Gesamtvergleich zwischen ihnen zu haben. @IMSoP

    – Nguyễn Văn Phong

    24. März 2021 um 4:40 Uhr

Benutzer-Avatar
Yousaf

Das .includes() Methode verwendet SameValueZero Algorithmus zur Überprüfung der Gleichheit zweier Werte und berücksichtigt die NaN Wert gleich sich selbst sein.

Das SameValueZero Algorithmus ist ähnlich wie SameValueaber der einzige Unterschied ist, dass die SameValueZero Algorithmus berücksichtigt +0 und -0 gleichwertig sein.

Das Object.is() Methode verwendet SameValue und es gibt true für zurück NaN.

console.log(Object.is(NaN, NaN));

Das Verhalten von .includes() Methode unterscheidet sich geringfügig von der .indexOf() Methode; das .indexOf() -Methode verwendet einen strengen Gleichheitsvergleich, um Werte zu vergleichen, und ein strenger Gleichheitsvergleich berücksichtigt dies nicht NaN sich selbst gleich sein.

console.log([NaN].indexOf(NaN));

Informationen zu verschiedenen Gleichheitsprüfungsalgorithmen finden Sie bei MDN:

MDN – Gleichheitsvergleiche und Gleichheit

Benutzer-Avatar
VLAZ

Spezifikationen

Dies scheint Teil der Number::sameValueZero abstrakter Betrieb:

6.1.6.1.15 Zahl::gleicherWertNull ( x, j )

  1. Wenn x ist NaN und j ist NaNRückkehr Stimmt.

[…]

Dieser Vorgang muss Teil des sein Array#includes() überprüfen, was:

22.1.3.13 Array.prototype.includes ( Suchelement [ , fromIndex ] )

[…]

  1. Wiederholen Sie, während k < len

    a. Lassen elementK das Ergebnis sein von ? Erhalten(Ö, ! ToString(k)).
    b. Wenn SameValueNull(Suchelement, elementK) ist StimmtRückkehr Stimmt.
    c. Setze k auf k + 1.

  2. Zurückkehren FALSCH.

[…]

Bei dem die SameValueZero Betrieb wird in Schritt 2 an die für Zahlen delegieren:

7.2.12 GleicherWertNull ( x, j )

[…]

  1. Wenn Typ (x) unterscheidet sich von Typ(j), Rückkehr FALSCH.
  2. Wenn Typ (x) ist dann Number oder BigInt
    a. Zurückkehren ! Typ(x::sameValueZero(x, j).
  3. Zurückkehren ! SameValueNonNumeric(x, j).

Zum Vergleich Array#indexOf() wird benutzen Strikter Gleichstellungsvergleich deswegen verhält es sich anders:

const arr = [NaN];
console.log(arr.includes(NaN)); // true
console.log(arr.indexOf(NaN));  // -1

Andere ähnliche Situationen

Andere Operationen, die verwenden SameValueZero Zum Vergleich sind in Sätzen und Karten:

const s = new Set();

s.add(NaN);
s.add(NaN);

console.log(s.size);     // 1
console.log(s.has(NaN)); // true

s.delete(NaN);

console.log(s.size);     // 0
console.log(s.has(NaN)); // false
const m = new Map();

m.set(NaN, "hello world");
m.set(NaN, "hello world");

console.log(m.size);     // 1
console.log(m.has(NaN)); // true

m.delete(NaN);

console.log(m.size);     // 0
console.log(m.has(NaN)); // false

Geschichte

Das SameValueZero Der Algorithmus taucht erstmals in den ECMAScript 6-Spezifikationen auf aber es ist ausführlicher. Es hat immer noch die gleiche Bedeutung und hat immer noch eine explizite:

7.2.10 SameValueZero(x, j)

[…]

  1. Wenn Typ (x) Zahl ist, dann a. Wenn x ist NaN und j ist NaNRückkehr Stimmt.
    […]

ECMAScript 5.1 hat nur eine SameValue Algorithmus was noch behandelt NaN gleicht NaN. Der einzige Unterschied zu SameValueZero ich zeige +0 und -0 werden behandelt: SameValue kehrt zurück false für sie, während SameValueZero kehrt zurück true.

SameValue wird hauptsächlich für interne Objektoperationen verwendet, daher ist es für das Schreiben von JavaScript-Code fast belanglos. Viele Verwendungen von SameValue sind, wenn mit Objektschlüsseln gearbeitet wird und es keine numerischen Werte gibt.

Das SameValue Die Operation wird direkt in ECMAScript 6 angezeigt, da das was ist Object.is() Verwendet:

console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0));   // false

Von geringem Interesse ist das WeakMap und WeakSet auch verwenden SameValue statt SameValueZero das Map und Set zum Vergleich verwenden. Jedoch, WeakMap und WeakSet Erlauben Sie nur Objekte als eindeutige Mitglieder, also versuchen Sie, a hinzuzufügen NaN oder +0 oder -0 oder andere Primitive führt zu einem Fehler.

  • Bedeutet „Wenn x ist NaN“bedeuten genau dasselbe wie “wenn isNaN(x)“? Oder bezieht es sich nur auf den einzelnen NaN-Wert, der von produziert wird NaN und nicht der gesamte Satz von NaN-Werten?

    – Ben Voigt

    23. März 2021 um 17:20 Uhr


  • @BenVoigt es ist im Wesentlichen dasselbe wie if (Number.isNaN(x)). Nun, das wäre das JavaScript-Äquivalent. Die Algorithmusschritte sind in Pseudocode. Die Implementierung soll prüfen, ob x ist der wörtliche Wert für NaN. Es gibt nur einen davon, aber verschiedene Dinge können ihn konvertieren (z. B. Number("apple")). Bearbeiten: Referenz für NaN.

    – VLAZ

    23. März 2021 um 17:23 Uhr


  • Es gibt definitiv mehrere NaN-Bitmuster in IEEE-754, und ich glaube, Sie können IEEE-754-Werte in Javascript übertragen, indem Sie zB einen typisierten Puffer verwenden. Meine Frage ist also, behandelt SameValueZero zwei verschiedene NaN-Bitmuster als gleich oder ungleich?

    – Ben Voigt

    23. März 2021 um 17:28 Uhr

  • @BenVoigt ah, ich denke, hier ist mein Wissen über IEEE-754 dünn. Aber laut Spec NaN ist ein NaN auch wenn es sich selbst nicht gleicht. Es sollte nur eine konzeptionelle geben. Ich nehme an, Implementierungen können beliebig viele verwenden NaN Werte, wie sie wollen, aber wenn der Algorithmus sagt x is NaN es bedeutet, gültig zu sein NaN Wert.

    – VLAZ

    23. März 2021 um 17:30 Uhr

Benutzer-Avatar
Nina Scholz

Im 7.2.16 Strikter Gleichheitsvergleichgibt es folgenden Hinweis:

HINWEIS

Dieser Algorithmus unterscheidet sich von dem GleicherWert Algorithmus bei der Behandlung von vorzeichenbehafteten Nullen und NaNs.

Dies bedeutet für Array#includes eine andere Vergleichsfunktion als beim strengen Vergleich:

22.1.3.13 Array.prototype.beinhaltet unter

NOTIZ 3

Das beinhaltet Methode unterscheidet sich bewusst von der ähnlichen Index von Methode auf zwei Arten. Erstens verwendet es die GleicherWertNull Algorithmus, statt Strikter Gleichstellungsvergleichsodass es erkannt werden kann NaN Array-Elemente. Zweitens werden fehlende Array-Elemente nicht übersprungen, anstatt sie wie zu behandeln nicht definiert.

Benutzer-Avatar
CcmU

Wie Sie beim Lesen sehen können Dokumentation beinhaltenes verwendet die sameValueZero Algorithmus zu arbeiten, so wie es ist Dokumentation sagen, es gibt a True Wert beim Vergleich von NaN und ich zitiere:

Wir können aus der Gleichheitsvergleichstabelle unten ersehen, dass dies auf die Art und Weise zurückzuführen ist, dass dies der Fall ist Object.is behandelt NaN. Beachten Sie, dass, wenn Object.is(NaN, NaN) als „false“ bewertet wird, wir sagen könnten, dass es als noch strengere Form von Triple Equals in das lockere/strenge Spektrum passt, eine Form, die zwischen -0 und +0 unterscheidet. Das NaN-Handling bedeutet jedoch, dass dies nicht wahr ist. Leider, Object.is muss im Hinblick auf seine spezifischen Merkmale betrachtet werden und nicht in Bezug auf die Lockerheit oder Strenge in Bezug auf die Gleichheitsoperatoren.

1258140cookie-checkWarum tut [NaN].includes(NaN) in JavaScript wahr zurückgeben?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy