Почему и как ([! []] + [] [[]]) [+! + [] + [+ []]] Оценивает букву "i"?

При чтении этой статьи, размещенной на dzone, я нашел фрагмент JavaScript, первоначально размещенный в Twitter Маркусом Лагергеном.

Следующий код, по-видимому, печатает строку "fail"

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

Это подразумевает неявное кастинг типов, и я пытаюсь понять, как именно эта строка интерпретируется.

Я выделил каждый символ

  • (![]+[])[+[]] prints "f"
  • (![]+[])[+!+[]] печатает "a"
  • ([![]]+[][[]])[+!+[]+[+[]]] печатает "i"
  • (![]+[])[!+[]+!+[]] prints "l"

Мне также удалось сломать выражения, возвращающие каждую букву, кроме "i"

письмо "f"

![] пустой массив - это объект, который согласно документации ECMAScript, пункт 9.2, оценивается до true при преобразовании в boolean, так что это false

false+[] в соответствии с пунктом 11.6.1 оба аргумента двоичного оператора + преобразуются в String, поэтому мы получаем "false"+"", который оценивает "false"

+[] Унарный оператор plus вызывает преобразование ToNumber, за которым следует преобразование ToPrimitive, если аргумент равен Object. Результат такого преобразования определяется вызовом внутреннего метода [[DefaultValue]] объекта. В случае пустого массива он по умолчанию равен 0. (Документация ECMAScript, разделы: 11.4.6, 9.3, 9.1)

"false"[0] мы обращаемся к символу с индексом 0, поэтому "f"

письмо "a"

В той же истории единственная разница здесь - это дополнительные преобразования в части в квадратных скобках (которая вычисляет число, указывающее на другой символ в строке "false"), вызванный использованием унарных + и ! операторов.

+[] оценивается как 0, как описано выше.

!0 оценивается как true, как определено в разделе Раздел 9.2 и Раздел 11.4.9. Во-первых, 0 преобразуется в boolean false, а затем оператор инвертирует значение.

+true снова, унарный плюс запускает преобразование ToNumber, которое возвращает 1 для двоичного true (раздел 11.4.6 и 9.3)

"false"[1] возвращает второй символ в строке, который равен "a"

буква "l"

!+[] оценивается как true, как описано выше

true+true, используя двоичный + для примитивов, запускает преобразование ToNumber. В случае истины его результат равен 1 и 1+1 равен 2

"false"[2] - самоочевидный

письмо "i"

Что оставляет меня в тупике - это письмо "i". Я вижу, что вторая часть (в квадратных скобках) оценивает строку "10" и что первая часть (в круглых скобках) возвращает "**************", но Я не могу делать головы или хвосты того, как это происходит. Может кто-нибудь объяснить это шаг за шагом? Особенно волшебство, которое случается с квадратными скобками? (массивы и доступ к массиву)

Если возможно, я хотел бы, чтобы каждый шаг содержал ссылку на основные правила ECMAScript.

То, что я нахожу самым загадочным, - это эта часть: [][[]]

2 ответа

Ваша загадочная часть не такая загадочная, если вы ее немного переписываете:

[]['']

[] будет принудительно введен в строку, потому что это не целое число, поэтому вы ищете свойство [] с именем '' (пустая строка). Вы просто получите undefined, так как нет свойства с этим именем.

Что касается фактической буквы, сложите выражение вверх на два основных компонента:

  • Строка ([![]]+[][[]]):
    • [![]] [false].
    • [][[]] - undefined.
    • Добавьте их вместе, и вы получите "**************".
  • И индекс: [+!+[]+[+[]]]. Некоторые пробелы и круглые скобки сделают операции более ясными: [+(!(+[])) + [+[]]]:
    • [+[]] [0].
    • +[] принуждает [] к целому числу, поэтому вы получаете 0.
    • !+[] принуждает 0 к булевому и отрицает его, поэтому вы получаете true.
    • +!+[] заставляет true целое число, поэтому вы получаете 1.
    • Добавьте их вместе, и вы получите ["10"].

При использовании строки для доступа к свойствам массива, и строка оказывается элементом массива, строка принудительно вводится в целое число и вы возвращаете фактический элемент массива:

> [1, 2, 3]["0"]
1
> [1, 2, 3]["1"]
2

Итак, ваш конечный результат:

> "**************"["10"]
"i"

Прочитайте этот ответ для объяснения части [false] + undefined.


([![]]+[][[]])[+!+[]+[+[]]] имеет две части:

([![]]+[][[]]), а другой, который вы нашли.

![] возвращает false. Затем мы используем [...] для получения .toString() поведения +. ([]+[] совпадает с [].toString()+[].toString()) [][[]] - undefined, потому что мы пытаемся получить доступ к индексу [] (или [].toString(), который является '') [], который равен undefined.

Извините за предыдущий ответ, я неправильно прочитал ваш комментарий.

licensed under cc by-sa 3.0 with attribution.