(! [] + []) [+ []]... Объясните, почему это работает

alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);

Выход этого кода: fail. Зачем?

Кстати, (![]+[])[+!+[]] == 'false'[1], right?. Но почему ![]+[] == "false" и почему +!+[] == 1?

Ответы

Ответ 1

Как отметил @Mauricio (![]+[])[+[]] - "f" (первый char "false" ), (![]+[])[+!+[]]) - "a" и т.д.

Как это работает?

Рассмотрим первый символ, 'f':

(![]+[])[+[]]; // 'f'

Первая часть выражения - между круглыми скобками - состоит из ![]+[], первый операнд оператора добавления - ![], и он будет создавать false, потому что объект массива - как и любой другой экземпляр объекта - является правдивым и применяет логический (!) НЕ унарный оператор, он производит, например, значение false.

![]; // false, it was truthy
!{}; // false, it was truthy
!0;  // true, it was falsey
!NaN;  // true, it was falsey

После этого у нас есть второй операнд сложения, пустой Array, [], это делается для преобразования значения false в String, поскольку строковое представление пустого массива - это просто пустая строка, эквивалентно:

false+[]; // "false"
false+''; // "false"

Последняя часть, пара квадратных скобок после круглых скобок, они являются аксессуарами свойств, и они получают выражение, которое формируется оператором Unary Plus, снова примененным к пустому массиву.

Что делает оператор Unary Plus, это преобразование типа, в Number, например:

typeof +"20"; // "number"

Еще один раз это применяется к пустому массиву, и, как я уже говорил, представление String массива представляет собой пустую строку, а когда вы конвертируете пустую строку в Number, она преобразуется в ноль:

+[]; // 0, because
+[].toString(); // 0, because
+""; // 0

Поэтому мы можем "декодировать" выражение в несколько шагов:

(![]+[])[+[]];
(false+[])[+[]];
(false+'')[+[]];
(false+'')[0];
('false')[0];  // "f"

Обратите внимание, что доступ к символам с использованием нотации скобок по значениям String не был частью ECMAScript 3rd. Edition, (поэтому метод charAt существовал).

Однако такие "свойства индекса", которые представляют символы строки, были стандартизованы на ECMAScript 5, и даже до стандартизации эта функция была доступна в большом количестве браузеров (даже в IE8 (режим стандартов)).