Как профессиональный математик, я вижу в операторе одинаковости Javscript ==
(также называемом «абстрактное сравнение», «слабое равенство» ) попытку построить отношение эквивалентности между сущностями, которое включает в себя рефлексивность , симметрию и переходность . К сожалению, два из этих трех основных свойств не работают:
A == A
может быть ложным, например
NaN == NaN // false
A == B
и B == C
вместе не подразумевают A == C
, например,
'1' == 1 // true
1 == '01' // true
'1' == '01' // false
A == B
подразумевает B == A
, что нарушение, вероятно, немыслимо в любом случае и приведет к серьезному восстанию;)
Почему отношения эквивалентности имеют значение?
Потому что это наиболее важный и распространенный тип отношений, поддерживаемый многочисленными примерами и приложениями. Наиболее важным применением является разложение сущностей на классы эквивалентности , что само по себе является очень удобным и интуитивно понятным способом понимания отношений. А отсутствие эквивалентности приводит к отсутствию классов эквивалентности, что, в свою очередь, приводит к отсутствию интуитивности и ненужной сложности, которая хорошо известна.
Почему такая ужасная идея писать ==
для отношения неэквивалентности?
Потому что это нарушает наше знакомство и интуицию, так как буквально любое интересное отношение сходства, равенства, конгруэнтности, изоморфизма, идентичности и т. Д. Является эквивалентностью.
Тип преобразования
Вместо того, чтобы полагаться на интуитивную эквивалентность, JavaScript вводит преобразование типов:
Оператор равенства преобразует операнды, если они не одного типа, затем применяет строгое сравнение.
Но как определяется преобразование типов? Через набор сложных правил с многочисленными исключениями?
Попытка построить отношение эквивалентности
Булевы. Понятно true
и false
не одно и то же и должно быть в разных классах.
Числа. К счастью, равенство чисел уже четко определено, в котором два разных числа никогда не находятся в одном классе эквивалентности. В математике это так. В JavaScript понятие числа несколько искажается из-за присутствия более экзотического -0
, Infinity
и -Infinity
. Наша математическая интуиция подсказывает , что 0
и -0
должно быть в том же классе (на самом деле -0 === 0
является true
), в то время как каждый из бесконечностей представляет собой отдельный класс.
Числа и логические значения. Учитывая количество классов, где мы можем поставить логические значения? false
становится похожим на 0
, тогда как true
становится похожим на 1
другое число:
true == 1 // true
true == 2 // false
Есть ли логика здесь , чтобы положить true
вместе с 1
? По общему признанию 1
различается, но это так -1
. Я лично не вижу смысла переходить true
на 1
.
И это становится еще хуже:
true + 2 // 3
true - 1 // 0
Так true
действительно превращается в 1
число! Это логично? Это интуитивно понятно? Ответ оставлен как упражнение;)
Но как насчет этого:
1 && true // true
2 && true // true
Единственное логическое x
с x && true
существом true
это x = true
. Что доказывает, что оба 1
и 2
(и любое другое число 0
) конвертируются в true
! То, что он показывает, - это то, что наше обращение не соответствует другому важному свойству - биекции . Это означает, что две разные сущности могут конвертировать в одну и ту же. Что само по себе не должно быть большой проблемой. Большая проблема возникает, когда мы используем это преобразование, чтобы описать отношение «одинаковости» или «свободного равенства» того, что мы хотим назвать. Но ясно одно - оно не будет отношением эквивалентности и не будет интуитивно описываться через классы эквивалентности.
Но можем ли мы сделать лучше?
По крайней мере, математически - определенно да! Простое отношение эквивалентности между булевыми и числами может быть построено только с false
и 0
быть в том же классе. Так false == 0
что было бы единственным нетривиальным свободным равенством.
А как насчет строк?
Мы можем обрезать строки из пробелов в начале и конце для преобразования в числа, также мы можем игнорировать нули перед:
' 000 ' == 0 // true
' 0010 ' == 10 // true
Таким образом, мы получаем простое правило для строки - обрезаем пробелы и нули впереди. Либо мы получим число, либо пустую строку, и в этом случае мы конвертируем в это число или ноль. Или мы не получаем число, в этом случае мы не конвертируем и поэтому не получаем новых отношений.
Таким образом, мы могли бы получить идеальное отношение эквивалентности для всего набора логических значений, чисел и строк! Кроме этого ... У разработчиков JavaScript, очевидно, другое мнение:
' ' == '' // false
Таким образом, две строки, в которые оба преобразуются 0
, неожиданно не похожи! Почему или почему? Согласно правилу, строки практически равны, когда они строго равны! Как мы видим, не только это правило нарушает транзитивность, но и избыточно! Какой смысл создавать другого оператора, ==
чтобы он был строго идентичен другому ===
?
Заключение
Оператор свободного равенства ==
мог бы быть очень полезным, если бы он соблюдал некоторые фундаментальные математические законы. Но, как это ни печально, его полезность страдает.