JavaScript и то, что вы о нем не знали: логические операции

Язык 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

Объяснение:

Спецификация строго определяет логику данного поведения:

  1. Если Type (x) отличается от Type (y), возвращается false.
  2. Если 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

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ