JavaScript и Batman

Sergey Ufocoder
Oct 31, 2020

--

Дополнение к статье: Насколько JavaScript сильный?

Забавный пример неявного преобразования в JavaScript:

const nope = Array(10).join("nope" - 1) + " Batman!";console.log(nope); //-> NaNNaNNaNNaNNaNNaNNaNNaNNaN Batman!

Это отсылка к вступлению анимационного телесериала про Бэтмена из шестидесятых. В сети также существует множество пародий, встречается даже кавер в metal стиле.

Давайте разберемся, почему получается именно такой результат. Выражение Array(10) создаст массив c десятью «пустыми» элементами:

Array(10)             // [empty × 10]
typeof Array(10)[0] // "undefined"

Метод массива Array.prototype.join конкатенирует элементы массива с использованием разделителя значений — аргумента separator. Метод приводит и аргумент separator и каждый элемент массива к строковому значению. Приведение происходит с помощью абстрактного оператора ToString, если элемент массива не является null или undefined.

Выдержка из спецификации:

Draft ECMA-262. 22.1.3.15 Array.prototype.join

Теперь давайте рассмотрим выражение:

"nope" - 1 // NaN

В этом выражение будет вызван The Subtraction Operator, где через цепочку внутренних операций в итоге будет выполнен оператор ApplyStringOrNumericBinaryOperator, в котором каждый из операндов приведется к типу Number.

Откуда получается, что:

"nope" - 1
Number("nope") - 1
NaN - 1 // NaN

Возвращаясь к работе метода join, получается, что 10 пустых строк будут соединены с помощью строки NaN, или другими словами получим 9 сконкатенированных строк “NaN”.

Array(10).join("nope" - 1)     + " Batman!";
Array(10).join("NaN") + " Batman!";
"NaNNaNNaNNaNNaNNaNNaNNaNNaN" + " Batman!";
"NaNNaNNaNNaNNaNNaNNaNNaNNaN Batman!";

В JavaScript нет никакой Магии, читайте спецификацию.

--

--