Комментарии 52
— !((null>0 | null==0) & null>=0)
!((null>0 | null==0) & null>=0) // true
(!(null>0 | null==0) & null>=0) // 1
Не силён в js, но видимо и этому есть разумное объяснение.
Конечно же есть, и очень простое. &
— это не булева операция, а численная; булева пишется как &&
.
В первом варианте получается
!((0 | 0) & 1) => !(0 & 1) => !(0) => true
а во втором
(!(0 | 0) & 1) => (!(0) & 1) => (1 & 1) => 1
> Если null < 0 принимает значение false, то null >= 0 принимает значение true
тут все логично
получается всю математическую логику ломает странный ==
Дело в том, что для того, что операторы сравнения работали разумно в нетипизированных языках нужно не два результата, а три:
true
, false
, unorderable types.Но поскольку PHP и JavaScript писались не для программистов, то было принято решение — программа должна работать любой ценой! Великолепное Job Security, так как без навешивания костылей (типа компилятора с TypeScript или ClojureScript) ошибки можно искать вечно…
Если нельзя вернуть неопределённый результат, а нужно вернуть только true или false, то как насчёт векторов, матриц? Если один вектор не меньше другого, это ведь не значит, что он больше или равен, это значит, что он не меньше, не больше, не равен и вообще не подлежит ранжированию. Так что с точки зрения математики определять один оператор через результат другого — глупо.
RelationalExpression : RelationalExpression >= ShiftExpression
1. Let lref be the result of evaluating RelationalExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be the result of evaluating ShiftExpression.
4. Let rval be ? GetValue(rref).
5. Let r be the result of performing Abstract Relational Comparison lval < rval.
6. ReturnIfAbrupt (r).
7. If r is true or undefined, return false. Otherwise, return true
Источник раздел 12.10 (осторожно, большая PDF)
Справедливости ради, эта строчка немного не точная:
Если null < 0 принимает значение false, то null >= 0 принимает значение true
Фактически, спецификация говорит о том, что нужно вернуть обратное значение операнду lval < rval
и справедлива для любого набора данных (кроме, разумеется undefined за счет ReturnIfAbrupt). В статье так и написано, но в переводе спецификации как-то странно, может в старой версии так и было.
А по-хорошему вообще ввести новый режим браузера, типа «use superstrict»: оставить там все лучшее и выкинуть устаревшее.
Следовательно, не совсем корректно undefined присваивать самостоятельно.
Я считаю, что надо ввести новое примитивное значение nil, семантический смысл которого — «просто нет значения». Nil будет унифицировать синтаксис и сочетать в себе лучшее от undefined и null. Сейчас по сути это и так происходит в TypeScript — при компиляции там не используется null и все решается через undefined. Я лишь предлагаю другое имя)
Сейчас по сути это и так происходит в TypeScript — при компиляции там не используется null и все решается через undefined.
А можно пруф?
null and undefined
В моем представлении (хотя я не теоретик программирования), в идеале, undefined — отдельный тип, а null и Na{N,T,etc} — значения, присутствующие в каждом типе. То есть undefined — это «NULL», а null — "\Lambda". И NaN (некорректное значение) нужен.
Представьте не переменные, а ассоциативный массив. Хотя тут в JavaScript'е не хватает «строгого» взятия элемента ассоциативного массива, с исключением в случе отсутствия в нем данного ключа.
Эх, наверное, заминусуют…
Но, порывшись, я понял, что спесификация со мной не согласна:
The undefined value is a primitive value used when a variable has not been assigned a value.
The null value is a primitive value that represents the null, empty, or non-existent reference.
А undefined — именно что нештатным, нетипизированным и разрушающим, для ошибочных ситуаций.
К сожалению, при создании первых версий js до этого не додумались, а потом уже было поздно.
И, на самом деле, в этом есть смысл. С точки зрения математики, если у нас есть два числа, x и y, и если x не меньше, чем y, тогда x должно быть больше чем y или равно ему.Нелогично. Тренарная логика и базы данных несогласны.
true, false, null, undefined это 3х или даже 4х арная логика.
С точки зрения математики, если у нас есть два числа, x и y, и если x не меньше, чем y, тогда x должно быть больше чем y или равно ему.
Тут-то всё логично, но раз уж схватились за математику, то этот код:
null > 0; // false
null == 0; // false
null >= 0; // true
с её точки зрения нарушает очевидное математическое утверждение:
A >= B это тоже самое, что A > B || A == B
console.log(x == x); // false
Вот как раз это было взято не с потолка, а из стандарта.
Что бы проверить NaN на NaN, надо использовать функцию «isNaN()»:
let x = 1 * undefined; // NaN
isNaN(x); // true
(x.toString() === "NaN"); // true
Ну бред же. a == b должно быть эквивалентно !(a<b) && !(b<a).
var mathTest1 = (null >= 0) ? true : false;
var mathTest2 = ((null > 0) || (null == 0)) ? true : false;
if(mathTest1 == mathTest2){
console.log('INFO: Все в порядке с логикой.');
}else if(mathTest1 != mathTest2){
console.log('WARNING: С логикой проблемы!');
}else{
console.log('ERROR: Что такое логика?');
}
Лично мое мнение, что это просто побочный эффект от преобразований, так как операторами > | >= | <= | < предпологается сравнение только чисел и больше ничего. Поэтому когда мы ими сравниваем:
+[] // 0
[] >= 0 // true
+null // 0
null >= 0 // true
+{} // NaN
({}) >= 0 // false
+undefined // NaN
undefined >= 0 // false
рантайм вначале берет и преобразовывает все в числа (преобразовывает так, как эти самые преобразования прописаны для каждого типа), потом сравнивает и выдает нам результат которому мы удивляемся.
Операторы == | === | != | !== в свою очередь предназначены для различных типов, поэтому преобразований не происходит:
null != 0 // true
null !== 0 // true
Некорректный результат сравнения null с 0
У Флэнагана есть интересная фраза:
Finally, note that the <= (less than or equal) and >= (greater than or equal) operators do
not rely on the equality or strict equality operators for determining whether two values
are “equal.” Instead, the less-than-or-equal operator is simply defined as “not greater
than,” and the greater-than-or-equal operator is defined as “not less than.
Т.е. можно представить себе, что >= и <= это не математические операторы, а свои JS’ие (со своими правилами), которые ни как не связаны с ==. Тогда опять же все становится логично:
0 < null -> false => 0 >= null -> true
0 > null -> false => 0 <= null -> true
JavaScript: загадочное дело выражения null >= 0