Come matematico professionista vedo nell'operatore identico di Javscript ==
( chiamato anche "confronto astratto", "uguaglianza libera" ) un tentativo di costruire una relazione di equivalenza tra entità, che include essere riflessivo , simmetrico e transitivo . Sfortunatamente, due di queste tre proprietà fondamentali falliscono:
A == A
può essere falso, ad es
NaN == NaN // false
A == B
e B == C
insieme non implicano A == C
, ad es
'1' == 1 // true
1 == '01' // true
'1' == '01' // false
Solo la proprietà simmetrica sopravvive:
A == B
implica B == A
che la violazione è probabilmente impensabile in ogni caso e porterebbe a una grave ribellione;)
Perché le relazioni di equivalenza contano?
Perché questo è il tipo di relazione più importante e prevalente, supportato da numerosi esempi e applicazioni. L'applicazione più importante è la scomposizione delle entità in classi di equivalenza , che è essa stessa un modo molto conveniente e intuitivo di comprendere le relazioni. E l'incapacità di essere equivalenza porta alla mancanza di classi di equivalenza, che a sua volta porta alla mancanza di intuitività e complessità non necessaria che è ben nota.
Perché è un'idea così terribile scrivere ==
per una relazione di non equivalenza?
Perché rompe la nostra familiarità e intuizione, poiché letteralmente qualsiasi relazione interessante di somiglianza, uguaglianza, congruenza, isomorfismo, identità ecc. È un'equivalenza.
Tipo di conversione
Invece di fare affidamento su un'equivalenza intuitiva, JavaScript introduce la conversione del tipo:
L'operatore di uguaglianza converte gli operandi se non sono dello stesso tipo, quindi applica un confronto rigoroso.
Ma come viene definita la conversione del tipo? Attraverso una serie di regole complicate con numerose eccezioni?
Tentativo di costruire una relazione di equivalenza
Booleani. Chiaramente true
e false
non sono gli stessi e dovrebbero essere in classi diverse.
Numeri. Fortunatamente, l'uguaglianza dei numeri è già ben definita, in cui due numeri diversi non fanno mai parte della stessa classe di equivalenza. In matematica, cioè. In JavaScript la nozione di numero è in qualche modo deformata dalla presenza del più esotico -0
, Infinity
e -Infinity
. La nostra intuizione matematica lo impone 0
e -0
dovrebbe essere nella stessa classe (in realtà lo -0 === 0
è true
), mentre ciascuna delle infinità è una classe separata.
Numeri e booleani. Date le classi numeriche, dove mettiamo i booleani? false
diventa simile a 0
, mentre true
diventa simile 1
ma nessun altro numero:
true == 1 // true
true == 2 // false
C'è qualche logica qui da mettere true
insieme 1
? Certamente 1
si distingue, ma lo è anche -1
. Io personalmente non vedo alcuna ragione per la conversione true
a 1
.
E va ancora peggio:
true + 2 // 3
true - 1 // 0
Quindi true
viene convertito in 1
tutti i numeri! È logico? È intuitivo? La risposta è lasciata come esercizio fisico;)
Ma che dire di questo:
1 && true // true
2 && true // true
L'unica booleana x
con x && true
l'essere true
è x = true
. Il che dimostra che entrambi 1
e 2
(e qualsiasi altro numero diverso da 0
) convertono in true
! Ciò che mostra è che la nostra conversione fallisce un'altra proprietà importante - essere la biiezione . Ciò significa che due entità diverse possono convertirsi nella stessa. Il che, di per sé, non deve essere un grosso problema. Il grosso problema sorge quando usiamo questa conversione per descrivere una relazione di "uguaglianza" o "uguaglianza libera" di qualunque cosa vogliamo chiamarla. Ma una cosa è chiara: non sarà una relazione di equivalenza e non sarà descritta in modo intuitivo tramite classi di equivalenza.
Ma possiamo fare di meglio?
Almeno matematicamente - sicuramente sì! Una semplice relazione di equivalenza tra valori booleani e numeri potrebbe essere costruita solo false
ed 0
essendo nella stessa classe. Quindi false == 0
sarebbe l'unica uguaglianza libera non banale.
E le stringhe?
Possiamo tagliare le stringhe dagli spazi bianchi all'inizio e alla fine per convertirli in numeri, inoltre possiamo ignorare gli zeri davanti:
' 000 ' == 0 // true
' 0010 ' == 10 // true
Quindi otteniamo una semplice regola per una stringa: tagliare gli spazi bianchi e gli zeri davanti. O otteniamo un numero o una stringa vuota, nel qual caso convertiamo in quel numero o zero. Oppure non otteniamo un numero, nel qual caso non ci convertiamo e quindi non otteniamo nuove relazioni.
In questo modo potremmo effettivamente ottenere una relazione di equivalenza perfetta sull'insieme totale di booleani, numeri e stringhe! Solo che ... i designer JavaScript ovviamente hanno un'altra opinione:
' ' == '' // false
Quindi le due stringhe in cui entrambe si convertono 0
sono improvvisamente non simili! Perché o perché? Secondo la regola, le stringhe sono vagamente uguali proprio quando sono rigorosamente uguali! Non solo questa regola rompe la transitività come vediamo, ma è anche ridondante! Qual è lo scopo di creare un altro operatore ==
per renderlo strettamente identico all'altro ===
?
Conclusione
L'operatore di uguaglianza allentata ==
avrebbe potuto essere molto utile se rispettasse alcune leggi matematiche fondamentali. Ma come purtroppo non fa, la sua utilità ne risente.