JavaScript и то, что вы о нем не знали: логические операции
Язык JavaScript замечательный. Он обладает до безобразия простым синтаксисом, большой экосистемой и, что самое важное, огромным комьюнити.
В то же время все мы знаем, что JavaScript – это также и довольно интересный язык, не лишенный хитростей. Некоторые из них могут быстро превратить повседневную работу программиста в ад, другие же заставят смеяться вслух.
Оригинальная идея проекта WTFJS принадлежит Брайану Леру. Этот список был создан на базе его яркой речи «WTFJS» с dotJS 2012:
https://www.youtube.com/watch?v=et8xNAc2ic8
Node Packaged Manuscript
Данное руководство можно установить с помощью nmp. Для этого выполните команду:
$ npm install -g wtfjs
Теперь вы можете воспользоваться командой wtfjs, которая откроет руководство в выбранном $PAGER. Тем не менее, более развернутый русскоязычный вариант вы найдете только в нашей статье.
Мотивация
Основная цель этого списка – собрать по-настоящему сумасшедшие примеры работы JavaScript и объяснить их принцип, если это возможно. Просто потому, что интересно узнать то, о чем мы раньше не знали.
Если вы новичок, воспользуйтесь данными заметками, чтобы реализовать более глубокое погружение в язык JavaScript. Приведенная информация должна мотивировать вас тратить больше времени на изучение спецификации. Если же вы профессиональный разработчик, рассматривайте это как ссылку на все причуды нашего любимого языка.
В любом случае, просто прочтите, и, вероятно, вы найдете для себя что-то новое.
Примечание
// -> используется для отображения результата выражения. Например:
1 + 1 // -> 2
//> показывает, каким будет консольный вывод. Например:
Console.log ('hello, world!') //> привет, мир!
// а это просто комментарий, используемый для объяснений. Пример:
// Назначение функции foo constant Const foo = function () {}
Язык JavaScript и принцип его работы с точки зрения логики
[] равняется ![]
Массив равен не массиву:
[] == ![] // -> true
Объяснение:
true – это false
!!'false' == !!'true' // -> true !!'false' === !!'true' // -> true
Объяснение:
Рассмотрим шаг за шагом:
true == 'true' // -> true false == 'false' // -> false // 'false' не является пустой строкой, поэтому 'true' !!'false' // -> true !!'true' // -> true
baNaNa
'b' + 'a' + + 'a' + 'a'
Язык JavaScript и олдскульная шутка, пусть и преобразованная на новый лад. Вот оригинал:
'Foo' + + 'bar' // -> 'fooNaN'
Объяснение:
Выражение воспринимается как «foo» + (+ «bar»), что преобразовывает «bar» в нечисло (Not-a-Number), и, следовательно, вместо «bar» мы получаем значение «NaN».
Но вот сам NaN в JavaScript – это не NaN
NaN === NaN // -> false
Объяснение:
Спецификация строго определяет логику данного поведения:
- Если Type (x) отличается от Type (y), возвращается false.
- Если Type (x) является числом, то:
- Если x является NaN, верните false.
- Если y является NaN, верните false.
Также следуя определению NaN из IEEE. Возможны четыре взаимоисключающих типа отношения: меньше, равно, больше и неупорядочено. Последний случай возникает, когда хотя бы один операнд является NaN. Каждое NaN будет сравнивать неупорядоченное со всем, включая себя.
«В чем смысл всех сравнений, возвращающих false, для значений IEEE754 NaN?» – из StackOverflow.
Это фейл
Вы не поверите, но ...
(! [] + []) [+ []] + (! [] + []) [+! + []] + ([! []] + [] [[]]) [+! + [] + [+ []]] + (! [] + []) [! + [] +! + []] // -> 'fail'
Объяснение:
Разбив эту массу символов на отдельные части, мы можем заметить, что:
(! [] + []) // -> 'false' ! [] // -> false
Поэтому мы пытаемся добавить [] к false. Но из-за ряда внутренних вызовов функций (binary + Operator -> ToPrimitive -> [[DefaultValue]]) мы заканчиваем преобразование правильного операнда в строку:
(! [] + []. ToString ()) // 'false'
Думая о строке как о массиве, мы можем получить доступ к ее первому символу через [0]:
'False' [0] // -> 'f'
Остальное очевидно, и только с i дела обстоят непросто. i захватывается в fail, создавая строку «falseundefined» и захватывая элемент по индексу ['10'].
[] – это правдиво, но не true
Массив является правдивым значением, однако он не равняется логическому представлению правды true. Рассмотрим ситуацию подробнее:
!! [] // -> true [] == true // -> false
Объяснение:
В данном случае могу поделиться только ссылками на соответствующие разделы о такой спецификации:
null является ложью, но не false
Язык JavaScript и еще одно явление из разряда «Необъяснимо, но факт». Несмотря на то, что значение null является ложным, оно не равняется логическому представлению неправды false.
!! null // -> false null == false // -> false
В то же время другие неправдивые значения, такие как 0 или ‘’, равны false.
0 == false // -> true '' == false // -> true
Объяснение:
Объяснение такое же, как и в предыдущем примере. Вот ссылка:
Заключение
Если говорить о JavaScript, как об отдельно существующем языке программирования, в его удобстве и функциональных возможностях нет никаких сомнений. Но, как и у любого языка, здесь есть специфические моменты, для понимания которых следует выкроить время, изучить информацию, рассмотреть примеры и прийти к определенным выводам.
Так или иначе, логика в приведенных «несостыковках» хромает только на первый взгляд, но если открыть документацию и провести параллели с некоторыми другими примерами, становится ясно, что язык JavaScript работает с точностью швейцарских часов.
Надеемся, наша статья оказалась для вас полезной. Напишите в комментариях, о каких еще интересных деталях в работе JavaScript вы знаете.
Также рекомендуем Вам посмотреть:
10 вещей, которые стоит знать каждому JavaScript-разработчику
Лучшие JavaScript фреймворки, библиотеки и инструменты в 2017
16 бесплатных книг по JavaScript
Огромный видеокурс по основам JavaScript от freeCodeCamp