Conosciamo molti operatori di confronto dalla matematica.
In JavaScript sono scritti così:
- Maggiore/meno di:
a > b
,a < b
. - Maggiore/meno che o uguale:
a >= b
,a <= b
. - Equale:
a == b
, si noti che il doppio segno di uguaglianza==
indica il test di uguaglianza, mentre uno singoloa = b
indica un’assegnazione. - Non è uguale. In matematica la notazione è
≠
, ma in JavaScript si scrivea != b
.
In questo articolo impareremo di più sui diversi tipi di confronto, come JavaScript li fa, incluse importanti peculiarità.
Alla fine troverete una buona ricetta per evitare problemi legati alle “stranezze di JavaScript”.
Booleano è il risultato
Tutti gli operatori di confronto restituiscono un valore booleano:
-
true
– significa “sì”, “corretto” o “la verità”. -
false
– significa “no”, “sbagliato” o “non la verità”.
Per esempio:
alert( 2 > 1 ); // true (correct)alert( 2 == 1 ); // false (wrong)alert( 2 != 1 ); // true (correct)
Un risultato di confronto può essere assegnato a una variabile, proprio come qualsiasi valore:
let result = 5 > 4; // assign the result of the comparisonalert( result ); // true
Confronto tra stringhe
Per vedere se una stringa è maggiore di un’altra, JavaScript usa il cosiddetto ordine “dizionario” o “lessicografico”.
In altre parole, le stringhe sono confrontate lettera per lettera.
Per esempio:
alert( 'Z' > 'A' ); // truealert( 'Glow' > 'Glee' ); // truealert( 'Bee' > 'Be' ); // true
L’algoritmo per confrontare due stringhe è semplice:
- Compara il primo carattere di entrambe le stringhe.
- Se il primo carattere della prima stringa è maggiore (o minore) di quello dell’altra stringa, allora la prima stringa è maggiore (o minore) della seconda. Abbiamo finito.
- Altrimenti, se i primi caratteri di entrambe le stringhe sono uguali, confrontare i secondi caratteri allo stesso modo.
- Ripetere fino alla fine di entrambe le stringhe.
- Se entrambe le stringhe finiscono alla stessa lunghezza, allora sono uguali. Altrimenti, la stringa più lunga è maggiore.
Nel primo esempio sopra, il confronto 'Z' > 'A'
arriva ad un risultato al primo passo.
Il secondo confronto 'Glow'
e 'Glee'
ha bisogno di più passi perché le stringhe sono confrontate carattere per carattere:
-
G
è uguale aG
. -
l
è uguale al
. -
o
è maggiore die
. Fermati qui. La prima stringa è maggiore.
L’algoritmo di confronto dato sopra è approssimativamente equivalente a quello usato nei dizionari o negli elenchi telefonici, ma non è esattamente lo stesso.
Per esempio, il caso conta. Una lettera maiuscola "A"
non è uguale alla minuscola "a"
. Quale è più grande? La minuscola "a"
. Perché? Perché il carattere minuscolo ha un indice maggiore nella tabella di codifica interna che JavaScript usa (Unicode). Torneremo ai dettagli specifici e alle conseguenze di questo nel capitolo Stringhe.
Confronto di tipi diversi
Quando si confrontano valori di tipi diversi, JavaScript converte i valori in numeri.
Per esempio:
alert( '2' > 1 ); // true, string '2' becomes a number 2alert( '01' == 1 ); // true, string '01' becomes a number 1
Per valori booleani, true
diventa 1
e false
diventa 0
.
Per esempio:
alert( true == 1 ); // truealert( false == 0 ); // true
È possibile che allo stesso tempo:
- Due valori siano uguali.
- Uno di essi è
true
come booleano e l’altro èfalse
come booleano.
Per esempio:
let a = 0;alert( Boolean(a) ); // falselet b = "0";alert( Boolean(b) ); // truealert(a == b); // true!
Dal punto di vista di JavaScript, questo risultato è abbastanza normale. Un controllo di uguaglianza converte i valori usando la conversione numerica (quindi "0"
diventa 0
), mentre la conversione esplicita Boolean
usa un altro insieme di regole.
Uguaglianza rigorosa
Un regolare controllo di uguaglianza ==
ha un problema. Non può differenziare 0
da false
:
alert( 0 == false ); // true
La stessa cosa accade con una stringa vuota:
alert( '' == false ); // true
Questo accade perché operandi di tipo diverso sono convertiti in numeri dall’operatore di uguaglianza ==
. Una stringa vuota, proprio come false
, diventa uno zero.
Come fare se vogliamo differenziare 0
da false
?
Un operatore di uguaglianza rigoroso ===
controlla l’uguaglianza senza conversione di tipo.
In altre parole, se a
e b
sono di tipo diverso, allora a === b
restituisce immediatamente false
senza un tentativo di conversione.
Proviamolo:
alert( 0 === false ); // false, because the types are different
C’è anche un operatore “strict non-equality” !==
analogo a !=
.
L’operatore di uguaglianza rigorosa è un po’ più lungo da scrivere, ma rende ovvio cosa sta succedendo e lascia meno spazio agli errori.
Confronto con null e undefined
C’è un comportamento non intuitivo quando null
o undefined
sono confrontati con altri valori.
Per un controllo di uguaglianza rigoroso===
Questi valori sono diversi, perché ognuno di loro è un tipo diverso.
alert( null === undefined ); // false
Per un controllo non rigoroso==
C’è una regola speciale. Questi due sono una “dolce coppia”: sono uguali tra loro (nel senso di ==
), ma non qualsiasi altro valore.
alert( null == undefined ); // true
per la matematica e altri confronti< > <= >=
null/undefined
sono convertiti in numeri: null
diventa 0
, mentre undefined
diventa NaN
.
Ora vediamo alcune cose divertenti che accadono quando applichiamo queste regole. E, cosa più importante, come non cadere in trappola con esse.
Strano risultato: null vs 0
Confrontiamo null
con uno zero:
alert( null > 0 ); // (1) falsealert( null == 0 ); // (2) falsealert( null >= 0 ); // (3) true
Matematica, questo è strano. L’ultimo risultato afferma che “null
è maggiore o uguale a zero”, quindi in uno dei confronti precedenti deve essere true
, ma sono entrambi falsi.
La ragione è che un controllo di uguaglianza ==
e i confronti > < >= <=
funzionano in modo diverso. I confronti convertono null
in un numero, trattandolo come 0
. Ecco perché (3) null >= 0
è vero e (1) null > 0
è falso.
D’altra parte, il controllo di uguaglianza ==
per undefined
e null
è definito in modo tale che, senza alcuna conversione, sono uguali tra loro e non sono uguali a nient’altro. Ecco perché (2) null == 0
è falso.
Un indefinito incomparabile
Il valore undefined
non dovrebbe essere paragonato ad altri valori:
alert( undefined > 0 ); // false (1)alert( undefined < 0 ); // false (2)alert( undefined == 0 ); // false (3)
Perché lo zero non piace così tanto? Sempre falso!
Abbiamo questi risultati perché:
- I confronti
(1)
e(2)
restituisconofalse
perchéundefined
viene convertito inNaN
eNaN
è un valore numerico speciale che restituiscefalse
per tutti i confronti. - Il controllo di uguaglianza
(3)
restituiscefalse
perchéundefined
è uguale solo anull
,undefined
, e nessun altro valore.
Evitare problemi
Perché abbiamo esaminato questi esempi? Dovremmo ricordarci sempre di queste particolarità? Beh, non proprio. In realtà, queste cose complicate diventeranno gradualmente familiari con il tempo, ma c’è un modo solido per evitare problemi con esse:
- Trattare qualsiasi confronto con
undefined/null
eccetto l’uguaglianza rigorosa===
con cura eccezionale. - Non usare confronti
>= > < <=
con una variabile che può esserenull/undefined
, a meno che tu non sia veramente sicuro di quello che stai facendo. Se una variabile può avere questi valori, controllate separatamente.
Sommario
- Gli operatori di confronto restituiscono un valore booleano.
- Le stringhe sono confrontate lettera per lettera nell’ordine del “dizionario”.
- Quando valori di tipo diverso sono confrontati, vengono convertiti in numeri (con l’esclusione di un controllo di uguaglianza rigoroso).
- I valori
null
eundefined
sono uguali==
tra loro e non sono uguali a nessun altro valore. - Fate attenzione quando usate confronti come
>
o<
con variabili che possono occasionalmente esserenull/undefined
. Controllare separatamente pernull/undefined
è una buona idea.