Это верно и возвращает строку "10"
в JavaScript ( больше примеров здесь ):
console.log(++[[]][+[]]+[+[]])
Почему? Что здесь происходит?
javascript
syntax
SapuSeven
источник
источник
+[]
приведение пустого массива к0
... затемОтветы:
Если мы разделим это, беспорядок равен:
В JavaScript это правда
+[] === 0
.+
преобразует что-то в число, и в этом случае оно сводится к+""
или0
(см. подробности спецификации ниже).Следовательно, мы можем упростить его (
++
имеет приоритет над+
):Потому что
[[]][0]
означает: получить первый элемент[[]]
, это правда, что:[[]][0]
возвращает внутренний массив ([]
). Из-за ссылок это неправильно[[]][0] === []
, но давайте вызовем внутренний массив,A
чтобы избежать неправильных обозначений.++
перед его операндом означает «увеличить на единицу и вернуть увеличенный результат». Так++[[]][0]
что эквивалентноNumber(A) + 1
(или+A + 1
).Опять же, мы можем упростить беспорядок в нечто более разборчивое. Давайте заменим
[]
обратноA
:Прежде чем
+[]
можно будет привести массив в число0
, его нужно сначала привести в строку, то есть""
снова. Наконец,1
добавляется, что приводит к1
.(+[] + 1) === (+"" + 1)
(+"" + 1) === (0 + 1)
(0 + 1) === 1
Давайте упростим это еще больше:
Кроме того, это верно в JavaScript:
[0] == "0"
потому что он объединяет массив с одним элементом. Присоединение объединит элементы, разделенные,
. С одним элементом вы можете сделать вывод, что эта логика приведет к самому первому элементу.В этом случае
+
видит два операнда: число и массив. Сейчас он пытается принудить двух к тому же типу. Сначала массив приведен в строку"0"
, затем номер приведен в строку ("1"
). Number+
String===
String .Детали спецификации для
+[]
:Это довольно лабиринт, но для этого
+[]
сначала он конвертируется в строку, потому что вот что+
говорит:ToNumber()
говорит:ToPrimitive()
говорит:[[DefaultValue]]
говорит:.toString
Массива говорит:Так
+[]
доходит до+""
, потому что[].join() === ""
.Опять же,
+
определяется как:ToNumber
определяется""
как:Так
+"" === 0
и так+[] === 0
.источник
true
случае, если значение и тип совпадают.0 == ""
возвращаетtrue
(то же самое после преобразования типа), но0 === ""
естьfalse
(не те же типы).1 + [0]
, а не"1" + [0]
потому, что++
оператор prefix ( ) всегда возвращает число. См. Bclary.com/2004/11/07/#a-11.4.4++[[]][0]
возвращает действительно1
, но++[]
выдает ошибку. Это замечательно, потому что, похоже++[[]][0]
, сводится к++[]
. Возможно, у вас есть идеи, почему++[]
выдает ошибку, а++[[]][0]
нет?PutValue
вызове (в терминологии ES3, 8.7.2) в операции префикса.PutValue
требует ссылки, тогда[]
как само по себе выражение не создает ссылку. Выражение, содержащее ссылку на переменную (скажем, мы определили ранее,var a = []
затем++a
работает) или доступ к свойству объекта (например,[[]][0]
), создает ссылку . Проще говоря, префиксный оператор не только создает значение, ему также нужно где-то поместить это значение.var a = []; ++a
,a
равно 1. После выполнения++[[]][0]
, массив , созданный[[]]
выражением теперь содержит только номер 1 по индексу 0.++
требует Reference , чтобы сделать это.Тогда у нас есть конкатенация строк
источник
===
, чем=>
?Нижеследующее адаптировано из поста в блоге, отвечающего на этот вопрос, который я разместил, когда этот вопрос еще был закрыт. Ссылки на (HTML-копию) спецификации ECMAScript 3, по-прежнему являются базовыми для JavaScript в современных широко используемых веб-браузерах.
Во-первых, комментарий: такого рода выражения никогда не появятся в какой-либо (вменяемой) производственной среде и могут использоваться только в качестве упражнения для определения того, насколько хорошо читатель знает грязные грани JavaScript. Общий принцип, что операторы JavaScript неявно преобразуют между типами, полезен, как и некоторые из общих преобразований, но большая часть деталей в этом случае - нет.
Выражение
++[[]][+[]]+[+[]]
может поначалу выглядеть довольно внушительно и неясно, но на самом деле его относительно легко разделить на отдельные выражения. Ниже я просто добавил скобки для ясности; Я могу заверить вас, что они ничего не меняют, но если вы хотите проверить это, не стесняйтесь читать об операторе группировки . Таким образом, выражение может быть более четко написано какРазбивая это, мы можем упростить, наблюдая, что
+[]
оценивает0
. Для того, чтобы удовлетворить себя , почему это так, проверьте унарный оператор + и следовать слегка извилистому следу , который заканчивается с ToPrimitive преобразования пустого массива в пустую строку, которая затем , наконец , превращается в0
по ToNumber . Теперь мы можем заменить0
каждый экземпляр+[]
:Уже проще. Что касается
++[[]][0]
, это комбинация префиксного оператора приращения (++
), литерала массива, определяющего массив с единственным элементом, который сам является пустым array ([[]]
) и свойством accessor ([0]
), вызываемым в массиве, определенном литералом массива.Итак, мы можем упростить
[[]][0]
до справедливости,[]
и мы имеем++[]
, верно? На самом деле, это не так, потому что оценка++[]
выдает ошибку, которая поначалу может показаться запутанной. Тем не менее, небольшое размышление о природе++
делает это ясным: оно используется для приращения переменной (например++i
) или свойства объекта (например++obj.count
). Он не только оценивает значение, но и сохраняет это значение где-то. В случае++[]
, ему некуда поставить новое значение (каким бы оно ни было), потому что нет ссылки на свойство объекта или переменную для обновления. В терминах спецификации это покрывается внутренней операцией PutValue , которая вызывается оператором приращения префикса.Итак, что же
++[[]][0]
делать? Ну, по той же логике+[]
, что и внутренний массив преобразуется в,0
и это значение увеличивается на,1
чтобы получить окончательное значение1
. Значение свойства0
во внешнем массиве обновляется до,1
и все выражение оценивается до1
.Это оставляет нас с
... который является простым использованием оператора сложения . Оба операнда сначала преобразуются в примитивы, и если любое из примитивов является строкой, выполняется конкатенация строк, в противном случае выполняется сложение чисел.
[0]
конвертируется в"0"
, поэтому используется конкатенация строк, производящая"10"
.В заключение, кое-что, что может быть не сразу очевидно, заключается в том, что переопределение одного из методов
toString()
илиvalueOf()
методовArray.prototype
изменит результат выражения, поскольку оба проверяются и используются, если они присутствуют, при преобразовании объекта в примитивное значение. Например, следующее... производит
"NaNfoo"
. Почему это происходит, оставлено в качестве упражнения для читателя ...источник
Давайте сделаем это просто:
источник
Этот оценивает то же самое, но немного меньше
так это оценивает
Итак, теперь вы получили это, попробуйте это:
источник
"10"
+ [] оценивается как 0 [...], затем суммируя (+ операция), что угодно, преобразует содержимое массива в его строковое представление, состоящее из элементов, соединенных запятой.
Все остальное, например получение индекса массива (имеет более высокий приоритет, чем операция +), является порядковым и ничего интересного.
источник
Возможно, кратчайшие возможные способы вычисления выражения в «10» без цифр:
+!+[] + [+[]]
// "10"-~[] + [+[]]
// "10"// ========== Объяснение ========== \\
+!+[]
:+[]
Конвертируется в 0.!0
конвертируется вtrue
.+true
преобразуется в 1.-~[]
=-(-1)
1[+[]]
:+[]
Преобразует в 0.[0]
это массив с единственным элементом 0.Затем JS оценивает
1 + [0]
, таким образом,Number + Array
выражение. Затем работает спецификация ECMA:+
оператор преобразует оба операнда в строку, вызываяtoString()/valueOf()
функции из базовогоObject
прототипа. Он работает как аддитивная функция, если оба операнда выражения являются только числами. Хитрость в том, что массивы легко преобразуют свои элементы в составное строковое представление.Некоторые примеры:
Есть хорошее исключение, которое
Objects
приводит к двум сложениямNaN
:источник
+ '' или + [] оценивает 0.
источник
[]
это не эквивалентно""
. Сначала элемент извлекается, затем конвертируется++
.Шаг за шагом,
+
превратить значение в число, и если вы добавите в пустой массив+[]
... так как он пуст и равен0
, он будетИтак, оттуда, теперь посмотрите на ваш код, это
++[[]][+[]]+[+[]]
...И между ними есть плюс
++[[]][+[]]
+[+[]]
Так что они
[+[]]
вернутся,[0]
поскольку у них есть пустой массив, который преобразуется0
в другой массив ...Итак, представьте, что первое значение представляет собой 2-мерный массив с одним массивом внутри ... поэтому
[[]][+[]]
будет равно,[[]][0]
которое вернет[]
...И в конце
++
преобразуйте его и увеличьте до1
...Таким образом, вы можете себе представить,
1
+"0"
будет"10"
...источник