Qual è la differenza tra (NaN! = NaN) e (NaN! == NaN)?


148

Prima di tutto voglio menzionare che so come isNaN()e come Number.isNaN()lavoro. Sto leggendo la guida definita di David Flanagan e mi dà un esempio di come verificare se il valore è NaN:

x !== x

Ciò comporterà truese e solo se lo xè NaN.

Ma ora ho una domanda: perché usa un confronto rigoroso? Perché sembra quello

x != x

si comporta allo stesso modo. È sicuro utilizzare entrambe le versioni o mi mancano alcuni valori in JavaScript che verranno restituiti trueper x !== xe falseper x != x?


10
È possibile che Flanagan preferisca semplicemente i !==controlli ai !=controlli. Per quanto ne so non c'è altro valore dove x != x. Ma ci sono due distinti gruppi di sviluppatori JavaScript: quelli che preferiscono !=e quelli che preferiscono !==, sia per velocità, chiarezza, espressività, ecc.
Steve Klösters,

30
Perché usare il confronto libero quando il confronto rigoroso si comporta allo stesso modo?
Ry-

3
@Raulucco: NaNnon è un tipo unico, è un numero. È un valore unico che non è uguale a se stesso.
TJ Crowder,

8
Il titolo sembra essere gente fuorviante. Suggerirei di cambiarlo in qualcosa del tipo "È x! = X mai diverso da x! == x?"
TJ Crowder,

6
@femmestem: Giorgi ha detto "in questo caso" è una questione di stile. Ed è corretto in questo. Non è stile quando i tipi di operandi sono diversi, ma è stile quando sono uguali. Separatamente: Flanagan sta facendo quei confronti ===con NaN per sottolineare che NaN non è uguale a se stesso. Non ha "torto", lo sta facendo come un esercizio di insegnamento, dimostrando che non funziona.
TJ Crowder,

Risposte:


128

Innanzitutto, vorrei sottolineare che NaNè un valore molto speciale: per definizione, non è uguale a se stesso. Ciò deriva dallo standard IEEE-754 su cui attingono i numeri JavaScript. Il valore "non un numero" non è mai uguale a se stesso, anche quando i bit corrispondono esattamente. (Che non sono necessariamente in IEEE-754, consente più valori diversi "non un numero"). Ecco perché anche questo viene fuori; tutti gli altri valori in JavaScript sono uguali a se stessi, NaNè semplicemente speciale.

... mi manca un valore in JavaScript che restituirà true per x! == x e false per x! = x?

No non siete. L'unica differenza tra !==e !=è che quest'ultimo farà la coercizione dei tipi, se necessario, per far sì che i tipi degli operandi siano gli stessi. In x != x, i tipi di operandi sono gli stessi, quindi è esattamente lo stesso di x !== x.

Ciò è chiaro dall'inizio della definizione dell'operazione di uguaglianza astratta :

  1. ReturnIfAbrupt (x).
  2. ReturnIfAbrupt (y).
  3. Se Tipo (x) è uguale a Tipo (y), allora

    Restituisce il risultato dell'esecuzione del confronto sull'uguaglianza rigorosa x === y.

  4. ...

I primi due passaggi sono idraulici di base. Quindi, in effetti, il primo passo di ==è vedere se i tipi sono gli stessi e, in tal caso, fare ===invece. !=e ne !==sono solo versioni negate.

Quindi, se Flanagan ha ragione, ciò NaNdarà solo per il vero x !== x, possiamo essere sicuri che è anche vero che solo il NaNdare per il vero x != x.

Molti programmatori JavaScript usano ===e !==per evitare alcune insidie ​​attorno alla coercizione del tipo che fanno gli operatori liberi, ma in questo caso non c'è nulla da leggere sull'uso dell'operatore rigoroso rispetto a quello libero.


Ho riletto la 4.9.1 - Equality and Inequality Operatorssezione e questa sembra essere la risposta. Il punto chiave per il ===confronto è: If the two values have the same type, test them for strict equality as described above. If they are strictly equal, they are equal. If they are not strictly equal, they are not equal.
Giorgi Nakeuri,

@GiorgiNakeuri: Non sono sicuro di quale 4.9.1 ti riferisca, forse il libro di Flanagan? Ma questo sta fondamentalmente dicendo ciò che la citazione dalle specifiche sopra sta dicendo, sì.
TJ Crowder,

2
Lo accetto perché risponde alla mia domanda in modo formalizzato e preciso. Grazie per le spiegazioni!
Giorgi Nakeuri,

1
@Moshe: cosa intendi con "attacchi live"? (Il termine non appare nelle specifiche.) Intendi qualcosa come l'esempio di GOTO 0 in cui aè effettivamente una funzione e non restituisce lo stesso valore due volte? Non è la stessa cosa di un valore per il quale !==sarebbe vero, che è ciò di cui l'OP ha chiesto. È solo una funzione che restituisce valori diversi. foo() !== foo()non è necessariamente vero, poiché foopotrebbe restituire valori diversi su ogni chiamata.
TJ Crowder,

1
@Moshe Beh, questo è un modo molto sgradevole per scherzare con proprietà e getter. Ma sembra essere praticamente lo stesso dell'esempio di GOTO 0, solo con un ulteriore livello di riferimento indiretto.
JAB

37

Ai fini di NaN, !=e !==fare la stessa cosa.

Tuttavia, molti programmatori evitano ==o !=in JavaScript. Ad esempio, Douglas Crockford li considera tra le " parti cattive " del linguaggio JavaScript perché si comportano in modi inaspettati e confusi:

JavaScript ha due serie di operatori di uguaglianza: ===e !==, e i loro gemelli malvagi ==e !=. I buoni funzionano come ti aspetteresti.

... Il mio consiglio è di non usare mai i gemelli cattivi. Invece, usa sempre ===e !==.


2
La domanda non riguarda NaN (nonostante il titolo). La domanda è "mi manca un valore in JavaScript che restituirà true per x! == x e false per x! = X?"
TJ Crowder,

@TJCrowder Due domande, davvero. La prima domanda è "È sicuro utilizzare entrambe le versioni" e la risposta è che entrambe le versioni sono equivalenti. Mi piace la tua risposta "nascosta" che spiega tutto in dettaglio.
jkdev,

22

Solo per divertimento, lascia che ti mostri un esempio artificiale in cui xnon lo è, NaNma gli operatori si comportano comunque diversamente. Per prima cosa definire:

Object.defineProperty(
  self,
  'x',
  { get: function() { return self.y = self.y ? 0 : '0'; } }
);

Poi abbiamo

x != x // false

ma

x !== x // true

9
Ha! :-) Ma è proprio qui che foo() != foo()foo restituisce 1 poi 2. Ad esempio, i valori non sono gli stessi, ma solo confrontando valori diversi.
TJ Crowder,

2

Voglio solo sottolineare che NaNnon è l'unica cosa che produce x !== xsenza usare l'oggetto globale. Esistono molti modi intelligenti per attivare questo comportamento. Eccone uno che usa i getter:

var i = 0, obj = { get x() { return i++; }};
with(obj) // force dynamic context, this is evil. 
console.log(x === x); // false

Come sottolineato da altre risposte, ==esegue la coerenza dei tipi, ma come in altre lingue e alla pari dello standard - NaN indica un errore di calcolo e per buoni motivi non è uguale a se stesso.

Per qualche ragione al di là di me la gente osserva questo problema con JS ma la maggior parte dei linguaggi che hanno il doppio (vale a dire C, Java, C ++, C #, Python e altri) mostrano questo comportamento esatto e la gente sta bene.


2
Sì, questo è esattamente ciò che @TJCrowder ha menzionato nel commento alla risposta di GOTO_0, non è vero?
Giorgi Nakeuri,

Potresti chiarire come ottenere l'ambigua coercizione dei tipi in queste altre lingue?
chicocvenancio,

0

Come a volte, le immagini sono meglio delle parole, controlla questa tabella (che è la ragione per cui faccio in modo che questa sia una risposta invece che un commento è perché ottiene una migliore visibilità).

Lì puoi vedere che il rigoroso confronto sull'uguaglianza (===) restituisce vero solo se il tipo e il contenuto corrispondono, quindi

var f = "-1" === -1; //false

Mentre il confronto astratto sull'uguaglianza (==) controlla solo il contenuto * convertendo i tipi e quindi confrontandoli rigorosamente:

var t = "-1" == -1; //true

Sebbene non sia chiaro, senza consultare l' ECMA , ciò che JavaScript considera durante il confronto, in un modo che il codice seguente valuta vero.

 var howAmISupposedToKnowThat = [] == false; //true
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.