Pull to refresh

Comments 52

— О великий JavaScript, будет ли зарплата в этом месяце?
— !((null>0 | null==0) & null>=0)
(+[![]]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]
UFO just landed and posted this here

Консоль MS Edge это не осилила, пришлось убивать процесс

На автомате скопировал ваш пример в консоль, сразу же заметил ещё одну странную особенность:
!((null>0 | null==0) & null>=0) // true
(!(null>0 | null==0) & null>=0) // 1

Не силён в js, но видимо и этому есть разумное объяснение.

Конечно же есть, и очень простое. & — это не булева операция, а численная; булева пишется как &&.

То есть в моём примере мы ещё и неявно кастуем из int в bool?
И в случае с !(((null>0 | null==0) & null>=0) + 1) мы зарплату не получим?
потому что там используются битовые операторы
В первом варианте получается
!((0 | 0) & 1) => !(0 & 1) => !(0) => true

а во втором
(!(0 | 0) & 1) => (!(0) & 1) => (1 & 1) => 1
Во втором видимо всё же:
(!(0 | 0) & 1) => (!(0) & 1) => (true & 1) => 1

Исходя из первого примера. Но сути не меняет, спасибо за полное пояснение, как говорится век живи — век учись.
казалось бы.
> Если null < 0 принимает значение false, то null >= 0 принимает значение true
тут все логично

получается всю математическую логику ломает странный ==
Там (так же, как и в PHP) всё странное. Для многих алгиритмов нужно отношение порядка или отношение эквивалентности. Ни того, ни другого ни PHP, ни в JavaScript по умолчанию нету — что совершенно логично (эксивалентность достигается с помощью ===, а порядок… нету порядка).

Дело в том, что для того, что операторы сравнения работали разумно в нетипизированных языках нужно не два результата, а три: true, false, unorderable types.

Но поскольку PHP и JavaScript писались не для программистов, то было принято решение — программа должна работать любой ценой! Великолепное Job Security, так как без навешивания костылей (типа компилятора с TypeScript или ClojureScript) ошибки можно искать вечно…
впринципе то понятно, null == 0 — False вполне логично… хотя в С будет True :)
Логично там, где есть разделение на ссылочные и примитивы. А в С null задефайнен на 0, и то не факт
ну да. раньше был просто дефайн сейчас неуверен.
UFO just landed and posted this here
«в нетипизированных языках» — в динамически типизируемых языках.
С этим согласен.

«Unorderable types» — Строго говоря это должно быть исключение.
Если в языке они предусмотрены, то да.
«И, на самом деле, в этом есть смысл. С точки зрения математики, если у нас есть два числа, x и y, и если x не меньше, чем y, тогда x должно быть больше чем y или равно ему.»
Если нельзя вернуть неопределённый результат, а нужно вернуть только true или false, то как насчёт векторов, матриц? Если один вектор не меньше другого, это ведь не значит, что он больше или равен, это значит, что он не меньше, не больше, не равен и вообще не подлежит ранжированию. Так что с точки зрения математики определять один оператор через результат другого — глупо.
Просто в вашем случае область определения функции сравнения иная — есть еще дискретный «некорректное значение». А здесь область определения чисто булева, так что все корректно.

Область значений, а не определения.

UFO just landed and posted this here
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). В статье так и написано, но в переводе спецификации как-то странно, может в старой версии так и было.

Авторы стандарта так и не решили для себя окончательно, что такое null — особый тип объекта или особый тип нуля, вот и получился баг в спецификации
Смотрящим за стандартом ES давно пора пометить undefined и null как obsolete и заменить на условный nil — «нет значения».
А по-хорошему вообще ввести новый режим браузера, типа «use superstrict»: оставить там все лучшее и выкинуть устаревшее.
Пожалуй, за undefined как раз и стоит похвалить JavaScript…
У него семантический смысл — переменной еще небыло присвоено значение.
Следовательно, не совсем корректно undefined присваивать самостоятельно.
Я считаю, что надо ввести новое примитивное значение nil, семантический смысл которого — «просто нет значения». Nil будет унифицировать синтаксис и сочетать в себе лучшее от undefined и null. Сейчас по сути это и так происходит в TypeScript — при компиляции там не используется null и все решается через undefined. Я лишь предлагаю другое имя)
Сейчас по сути это и так происходит в TypeScript — при компиляции там не используется null и все решается через undefined.

А можно пруф?

Для меня undefined — «значения нет», null — «пустое значение». Условно говоря, переменная — ссылка, undefined — отсутствие значения у этой ссылки, а null — отсутствие значения по ссылке. То есть, если мы не можем найти значение чего-либо — имеем undefined, если можем, но оно пустое — то null.

В моем представлении (хотя я не теоретик программирования), в идеале, 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.
Именно такое значение по спецификации я имею ввиду — она очень уж узко определяет эти вещи. Думаю в будущем это будет исправлено и унифицировано. Самый простой вариант на данный момент — просто отказаться от null и принять undefined за «просто нет значения», как Вы и считали изначально)
Вообще, конечно, null должен быть «пустым значением» (математики бы назвали единицей относительно операции сложения для данного типа). Числом 0, пустой строкой, массивом из 0 элементов, пустым объектом без свойств. Но при этом — штатным значением, неразрушающим другие значения при участии в операциях, и, главное, типизированным. И не для каждого типа вообще существовать (примеры типов без нуля: boolean, сложные классы типа user и т.д.)
А undefined — именно что нештатным, нетипизированным и разрушающим, для ошибочных ситуаций.
К сожалению, при создании первых версий js до этого не додумались, а потом уже было поздно.
UFO just landed and posted this here
И, на самом деле, в этом есть смысл. С точки зрения математики, если у нас есть два числа, 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
Ну с математикой там всё сложно, особенно если учесть что null <= 0 тоже true, а значит null это 0.

Это скорее возможное определение, чем осмысленное утверждение.

Вот как раз это было взято не с потолка, а из стандарта.

NaN — это псевдочисло, любые арифметические операции с которымм всегда возвращают NaN, а операции сравнения всегда возвращают false.
Что бы проверить NaN на NaN, надо использовать функцию «isNaN()»:
let x = 1 * undefined; // NaN

isNaN(x); // true

(x.toString() === "NaN"); // true
isNaN именно так и определяется, через return !(x==x)
isNaN именно так и определяется, через return !(x==x)
А что если число вещественное? Они ведь то же с этим оператором не дружат.
Не помню правда, для одной и той же переменной это справедливо или нет.

Ну бред же. a == b должно быть эквивалентно !(a<b) && !(b<a).

Должно для чего? Для частично упорядоченных множеств это неверно.

Ну ок, неверно. Но тогда и то что a>=b эквивалентно !(a<b) тоже неверно.

Да, a>=b (понимаемое как a>b || a=b), не эквивалентно !(a<b). Но в данном случае a>=b равно !(a<b) по определению.

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: Что такое логика?');
}

Результат
WARNING: С логикой проблемы!

Лично мое мнение, что это просто побочный эффект от преобразований, так как операторами > | >= | <= | < предпологается сравнение только чисел и больше ничего. Поэтому когда мы ими сравниваем:


+[]         // 0
[] >= 0     // true

+null       // 0
null >= 0   // true

+{}         // NaN
({}) >= 0   // false

+undefined      // NaN
undefined >= 0  // false

рантайм вначале берет и преобразовывает все в числа (преобразовывает так, как эти самые преобразования прописаны для каждого типа), потом сравнивает и выдает нам результат которому мы удивляемся.


Операторы == | === | != | !== в свою очередь предназначены для различных типов, поэтому преобразований не происходит:


null != 0    // true
null !== 0  // true
null – это отсутствие значения, т.е. это не 0, т.к. 0 – это все же значение, поэтому, для меня, null == 0 -> false – это логично.
У Флэнагана есть интересная фраза:
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
Sign up to leave a comment.