@Ventus

Как складывается отрицание (!) и пустой массив?

Знакомый показал интересный пример, который ему задали на собеседовании. Я до сих пор не могу до конца уловить смысл.
console.log( ! + [] + !![] ) // 2

Я не понимаю, почему ! + [] === true.

Правильно ли я мыслю: сначала пустой массив приводится к числовому типу, что будет равно 0. Далее этот 0 приводится к логическому типу благодаря знаку отрицания (!) и становится единицей. Единица в логическом типе === true. Далее true + !![] === true + true. В числовом типе true === 1. Соответственно, 1 + 1 = 2.

Но я не понимаю, как происходил сложение между ! и []. И почему пустой массив приводится к числовому типу, если его складывают с логическим оператором. Если привести пустой массив к булевому типу, то результат будет false.
  • Вопрос задан
  • 105 просмотров
Решения вопроса 1
@ned4ded
Верстка, Фронтенд
Очень спорный вопрос для собеседования, откровенно говоря.

Операторы сложения и вычитания имеют унарную версию: употребление такого оператора перед значением конвертирует значение в числовое.
console.log(+"1"); // prints 1
console.log(+"s"); // prints NaN


В случае +[], что эквивалентно Number([]), массив преобразуется в 0. Соответственно в операции !+[] используется 2 оператора подряд (например, как !! во второй части выражения), сначала происходит преобразование массива в ноль с помощью унарного оператора сложения +[] и конвертация нуля в true с помощью оператора !. В первой части выражения получаем true.

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

В итоге (!(+[])) + (!![]) (я позволил себе расставить скобки, чтобы был более очевиден порядок выполнения), конвертится в true + true, что конвертится в 1 + 1, собственно, вот и ваша двойка.

ps Я хз, люди, которые составляют такие задачи, видимо, просто глумятся.

более наглядная последовательность преобразований:
!+[] + !![];
 
/* +[] converts to 0 */

!0 + !![];

/* !0 converts to true */

true + !![];

/* ![] converts to false */

true + !false;

/* !false coverts to true */

true + true;

/* both true values convert to numbers */

1 + 1;

/* equals 2 */


Небольшой апдейт. На немой вопрос "почему конвертация массива в число дает 0, а конвертация массива в булевой тип дает true, тогда как true != 0?" можно ответить след. образом:
а) Почему конвертация массива в число дает 0? Массив является объектом в js, для конвертации объекта в число его нужно сначала конвертировать в примитив. В данном случае для простого объекта вызывается метод toString(). Метод toString() на массиве возвращает конкатенацию строковых значений массива, что для пустого массива дает пустую строку "". Подробнее о логике конвертации объекта в примитив в спеке, ecma-262/5.1/9.1. Далее конвертируется строка в число, что для пустой строки равно 0, подробнее пункт 9.3.1 спеки.

б) Почему конвертация массива в булевый тип дает true? Простой ответ: согласно пункту 9.2 спецификации. Если поразмышлять, то скорее всего это означает, что объект существует (а он не может не существовать, если существует ссылка на него).
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
0xD34F
@0xD34F Куратор тега JavaScript
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы