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

Комментарии

ВАКАНСИИ

Добавить вакансию
Flutter Developer
по итогам собеседования
AppSec BP
по итогам собеседования

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