Jako profesjonalny matematyk widzę w operatorze podobieństwa Javscript ==
( zwanym także „porównaniem abstrakcyjnym”, „luźną równość” ) próbę zbudowania relacji równoważności między jednostkami, która obejmuje bycie zwrotnym , symetrycznym i przechodnim . Niestety dwie z tych trzech podstawowych właściwości zawodzą:
A == A
może być fałszywe, np
NaN == NaN // false
A == B
i B == C
razem nie oznaczają A == C
, np
'1' == 1 // true
1 == '01' // true
'1' == '01' // false
Przetrwa tylko własność symetryczna :
A == B
sugeruje B == A
, które naruszenie jest w każdym razie nie do pomyślenia i doprowadziłoby do poważnego buntu;)
Dlaczego stosunki równoważności mają znaczenie?
Ponieważ jest to najważniejszy i najczęstszy rodzaj relacji, poparty licznymi przykładami i aplikacjami. Najważniejszą aplikacją jest rozkład jednostek na klasy równoważności , co samo w sobie jest bardzo wygodnym i intuicyjnym sposobem rozumienia relacji. Brak równoważności prowadzi do braku klas równoważności, co z kolei prowadzi do znanego braku intuicyjności i niepotrzebnej złożoności.
Dlaczego tak okropny jest pomysł na pisanie ==
relacji nierównomierności?
Ponieważ niszczy naszą znajomość i intuicję, ponieważ dosłownie każda interesująca relacja podobieństwa, równości, kongruencji, izomorfizmu, tożsamości itp. Jest równoważna.
Konwersja typu
Zamiast polegać na intuicyjnej równoważności, JavaScript wprowadza konwersję typu:
Operator równości konwertuje operandy, jeśli nie są tego samego typu, a następnie stosuje ścisłe porównanie.
Ale jak definiuje się konwersję typu? Poprzez zestaw skomplikowanych zasad z licznymi wyjątkami?
Próba zbudowania relacji równoważności
Booleany. Oczywiście true
i false
nie są takie same i powinny być w różnych klasach.
Liczby. Na szczęście równość liczb jest już dobrze zdefiniowana, w której dwie różne liczby nigdy nie należą do tej samej klasy równoważności. To znaczy w matematyce. W JavaScript pojęcie liczby jest nieco zdeformowane przez obecność bardziej egzotycznych -0
, Infinity
i -Infinity
. Nasza intuicja matematyczna dyktuje to 0
i -0
powinna należeć do tej samej klasy (w rzeczywistości -0 === 0
jest true
), podczas gdy każda z nieskończoności jest odrębną klasą.
Liczby i liczby booleańskie. Biorąc pod uwagę klasy liczbowe, gdzie umieszczamy booleany? false
staje się podobny do 0
, podczas gdy true
staje się podobny do, 1
ale nie ma innej liczby:
true == 1 // true
true == 2 // false
Czy jest jakaś logika tutaj umieścić true
razem z 1
? Wprawdzie 1
wyróżnia się, ale tak też jest -1
. Ja osobiście nie widzę żadnego powodu, aby przekształcić true
się 1
.
I staje się jeszcze gorzej:
true + 2 // 3
true - 1 // 0
Tak więc true
rzeczywiście jest przeliczany na 1
wszystkie liczby! Czy to logiczne? Czy to jest intuicyjne? Odpowiedź pozostawia się jako ćwiczenie;)
Ale co z tym:
1 && true // true
2 && true // true
Jedyna logiczna x
z x && true
istoty true
jest x = true
. Co dowodzi, że zarówno 1
i 2
(i każda inna liczba niż 0
) przekształcają się true
! Pokazuje to, że nasza konwersja zawodzi inna ważna właściwość - biject . Oznacza to, że dwa różne podmioty mogą konwertować na ten sam. Co samo w sobie nie musi stanowić dużego problemu. Duży problem powstaje, gdy używamy tej konwersji do opisania relacji „identyczności” lub „luźnej równości” tego, co chcemy to nazwać. Ale jedno jest jasne - nie będzie to relacja równoważności i nie będzie intuicyjnie opisana za pomocą klas równoważności.
Ale czy możemy zrobić lepiej?
Przynajmniej matematycznie - zdecydowanie tak! Prosty relacja równoważności między logicznych i numery mogą być zbudowane z tylko false
i 0
będąc w tej samej klasie. Tak false == 0
byłoby tylko nietrywialne luźne równość.
Co z ciągami znaków?
Możemy przycinać ciągi znaków z białych znaków na początku i na końcu, aby konwertować na liczby, a także możemy ignorować zera z przodu:
' 000 ' == 0 // true
' 0010 ' == 10 // true
Otrzymujemy więc prostą regułę dla ciągu - przycinaj białe spacje i zera z przodu. Otrzymujemy liczbę lub pusty ciąg, w którym to przypadku konwertujemy na tę liczbę lub zero. Lub nie otrzymujemy numeru, w którym to przypadku nie dokonujemy konwersji, więc nie otrzymujemy żadnej nowej relacji.
W ten sposób moglibyśmy uzyskać idealną relację równoważności całkowitego zestawu wartości logicznych, liczb i ciągów! Tyle że ... projektanci JavaScript mają oczywiście inną opinię:
' ' == '' // false
Zatem dwa ciągi, na które oba konwertują, 0
nagle stają się niepodobne! Dlaczego lub dlaczego Zgodnie z regułą struny są luźno równe dokładnie wtedy, gdy są ściśle równe! Ta reguła nie tylko łamie przechodniość, jak widzimy, ale także jest zbędna! Po co tworzyć innego operatora, ==
aby był ściśle identyczny z drugim ===
?
Wniosek
Luźny operator równości ==
mógłby być bardzo przydatny, gdyby przestrzegał podstawowych praw matematycznych. Ale jak to niestety nie działa, jego użyteczność cierpi.