alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);
Выход этого кода: fail
. Зачем?
Кстати, (![]+[])[+!+[]] == 'false'[1]
, right?. Но почему ![]+[] == "false"
и почему +!+[] == 1
?
alert((![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]);
Выход этого кода: fail
. Зачем?
Кстати, (![]+[])[+!+[]] == 'false'[1]
, right?. Но почему ![]+[] == "false"
и почему +!+[] == 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 (режим стандартов)).