(! [] + []) [+ []]… Поясніть, чому це працює


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

Вихідний сигнал цього коду: fail. Чому?

До речі (![]+[])[+!+[]] == 'false'[1], так? Але чому ![]+[] == "false"і чому +!+[] == 1?


14
@Snoob Я не вірю тобі. Зрештою, це вилка бомба.
Йоханнес Шауб - ліб

3
Звичайно, це буквальний рядок;)
Йі Цзян

3
(![]+[])[+[]]є "f" (перший знак від "false"), (![]+[])[+!+[]]"a" і т. д.
Маурісіо Шеффер

3
@Snoob: як ви вже говорили, ви можете перевірити кожен вираз у своєму браузері. Спробуйте alert(![]+[])тоді, alert(+!+[])і ви побачите.
Маурісіо Шеффер

12
Марно чи ні, я вважаю це цікавим питанням і хотів би побачити чітко викладене пояснення. Багато кодових гольфів було б закрито, якби враховувались корисність чи практичність. Вправи та ігри корисні самі по собі для розширення розуму та мислення.
Джон К

Відповіді:


127

Як @Mauricio прокоментував (![]+[])[+[]]це "f" (перший знак "false"), (![]+[])[+!+[]])це "a" тощо.

Як це працює?

Розглянемо перший символ, 'f':

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

Перша частина виразу - між дужками - складається з ![]+[], перший операнд оператора Addition є, ![]і він буде виробляти false, тому що об’єкт масиву - як і будь-який інший екземпляр Object - є truthy і застосовує логічний (!) НЕ одинаковий оператора, він виробляє значення false, наприклад.

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

Після цього у нас є другий операнд доповнення, порожній масив. []Це зроблено просто для перетворення falseзначення в String, тому що рядкове представлення порожнього масиву є просто порожнім рядком, еквівалентне:

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

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

Оператор Unary Plus - це перетворення типу Number, наприклад:

typeof +"20"; // "number"

Ще раз це застосовується до порожнього масиву, і, як я вже говорив раніше, рядкове представлення масиву є порожнім рядком, і коли ви перетворюєте порожній рядок у число, він перетворюється на нуль:

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

Тому ми можемо "розшифрувати" вираз у кілька кроків:

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

Зауважте, що доступ до символів за допомогою позначення дужок на значеннях String не був частиною ECMAScript 3rd. Специфікація видання (саме тому charAtметод існував).

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


46
Просто сподіваюся, що це ніколи не питання інтерв'ю.
Inisheer

4
@JTA: Я сподіваюся , що це є ! Я пройшов би :-D
Маурісіо Шеффер

18
Звідки походить "я"?
Джош Стодола

5
@rlemon, intна мові не існує типу даних, насправді всі номери мають 64-розрядний формат подвійної точності (значення IEEE 754), хоча деякі оператори працюють із значеннями Integer (як битові оператори), результат завжди подвійний . Цей 'i'приклад приходить з undefined, але це може бути, Infinityнаприклад: (+!+[]/+[+[]]+[])[!+[]+!+[]+!+[]]=> (1/0+'')[3]=> (Infinity+'')[3]=>'i'
CMS

5
@JoshStodola Ну, через 3 місяці, подальше уточнення. "Я" в цьому випадку походить від "невизначеного", так, але тут є ще одна хитрість. Код об'єднує "false" у "undefined", щоб утворити "falseundefined"(побудований за допомогою [![]]+[][[]]:), в якому індекс "i" дорівнює 10. +!+[]+[+[]]дає "10". Це використовується для вилучення "i" (Строкові індекси можна використовувати в javascript, якщо їх, мабуть, примушують до цілих чисел). Кінцева конструкція , яка виробляє це:([![]]+[][[]])[+!+[]+[+[]]]
ентропія
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.