JavaScript и Batman
Дополнение к статье: Насколько 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
.
Выдержка из спецификации:
Теперь давайте рассмотрим выражение:
"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 нет никакой Магии, читайте спецификацию.