Как профессиональный математик, я вижу в операторе одинаковости 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, неожиданно не похожи! Почему или почему? Согласно правилу, строки практически равны, когда они строго равны! Как мы видим, не только это правило нарушает транзитивность, но и избыточно! Какой смысл создавать другого оператора, ==чтобы он был строго идентичен другому ===?
Заключение
Оператор свободного равенства ==мог бы быть очень полезным, если бы он соблюдал некоторые фундаментальные математические законы. Но, как это ни печально, его полезность страдает.