Це дійсно і повертає рядок "10"у JavaScript ( більше прикладів тут ):
console.log(++[[]][+[]]+[+[]])
Чому? Що тут відбувається?
Це дійсно і повертає рядок "10"у JavaScript ( більше прикладів тут ):
console.log(++[[]][+[]]+[+[]])
Чому? Що тут відбувається?
Відповіді:
Якщо ми розділимо його, безлад дорівнює:
++[[]][+[]]
+
[+[]]
У JavaScript це правда +[] === 0. +перетворює щось у число, і в цьому випадку воно зводиться до +""або 0(див. деталі специфікації нижче).
Тому ми можемо спростити це ( ++має перевагу над +):
++[[]][0]
+
[0]
Тому що [[]][0]означає: отримати перший елемент від [[]], це правда, що:
[[]][0]повертає внутрішній масив ( []). Через посилання неправильно говорити [[]][0] === [], але давайте зателефонуємо до внутрішнього масиву, Aщоб уникнути неправильних позначень.
++перед його операндом означає «приріст на одиницю і повернення нарощеного результату». Так що ++[[]][0]еквівалентно Number(A) + 1(або +A + 1).
Знову ж таки, ми можемо спростити безлад у щось більш розбірливе. Підставами []назад на A:
(+[] + 1)
+
[0]
Перш ніж +[]можна примусити масив до числа 0, його потрібно спочатку зв'язати в рядок, тобто ""знову. Нарешті, 1додається, що призводить до 1.
(+[] + 1) === (+"" + 1)(+"" + 1) === (0 + 1)(0 + 1) === 1Давайте ще більше спростимо це:
1
+
[0]
Також це справедливо в JavaScript:, [0] == "0"тому що це об'єднання масиву з одним елементом. Приєднання об'єднає елементи, розділені на ,. З одного елемента можна зробити висновок, що ця логіка спричинить за собою перший елемент.
У цьому випадку +бачить два операнди: число та масив. Зараз він намагається примусити обох до одного типу. Спочатку масив примушується до рядка "0", далі число примушується до рядка ( "1"). Кількість +рядків ===Рядок .
"1" + "0" === "10" // Yay!
Деталі специфікації для +[]:
Це доволі лабіринт, але для цього +[]спочатку він перетворюється на рядок, тому що це +говорить:
11.4.6 Одинарний + Оператор
Оператор unary + перетворює свій операнд у тип Number.
Виробництво UnaryExpression: + UnaryExpression оцінюється наступним чином:
Нехай expr є результатом оцінки UnaryExpression.
Повернути ToNumber (GetValue (expr)).
ToNumber() каже:
Об'єкт
Застосуйте наступні дії:
Нехай primValue буде ToPrimitive (вхідний аргумент, натяк String).
Повернути ToString (primValue).
ToPrimitive() каже:
Об'єкт
Повернути для об'єкта значення за замовчуванням. Значення об'єкта за замовчуванням отримується за допомогою виклику внутрішнього методу [[DefaultValue]], передаючи необов'язковий підказку PreferredType. Поведінка внутрішнього методу [[DefaultValue]] визначається цією специфікацією для всіх власних об'єктів ECMAScript у 8.12.8.
[[DefaultValue]] каже:
8.12.8 [[DefaultValue]] (підказка)
Коли внутрішній метод O [[DefaultValue]] викликається з рядком підказки, виконуються наступні кроки:
Нехай toString є результатом виклику внутрішнього методу [[Get]] об'єкта O з аргументом "toString".
Якщо IsCallable (toString) відповідає дійсності,
а. Нехай str є результатом виклику внутрішнього методу [[Call]] toString, причому O це значення і порожній список аргументів.
б. Якщо str - це примітивне значення, поверніть str.
.toStringМасиву каже:
15.4.4.2 Array.prototype.toString ()
Коли викликається метод toString, виконуються наступні кроки:
Нехай масив є результатом виклику ToObject на це значення.
Нехай функція є результатом виклику внутрішнього методу масиву [[Get]] з аргументом "приєднатися".
Якщо IsCallable (func) помилковий, то нехай func є стандартним вбудованим методом Object.prototype.toString (15.2.4.2).
Поверніть результат виклику внутрішнього методу функціонування [[Call]] функціонального забезпечення масиву як цього значення та порожнього списку аргументів.
Так +[]зводиться до +"", тому що [].join() === "".
Знову ж таки, +визначається як:
11.4.6 Одинарний + Оператор
Оператор unary + перетворює свій операнд у тип Number.
Виробництво UnaryExpression: + UnaryExpression оцінюється наступним чином:
Нехай expr є результатом оцінки UnaryExpression.
Повернути ToNumber (GetValue (expr)).
ToNumberвизначається ""як:
MV для StringNumericLiteral ::: [порожній] дорівнює 0.
Отже +"" === 0, і таким чином +[] === 0.
trueвипадку, якщо значення і тип однакові. 0 == ""повертає true(те саме після перетворення типів), але 0 === ""є false(не однакових типів).
1 + [0], ні "1" + [0], тому що ++оператор префікса ( ) завжди повертає число. Дивіться 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. для цього ++потрібна посилання.
++[[]][+[]] => 1 // [+[]] = [0], ++0 = 1
[+[]] => [0]
Тоді у нас є з'єднання рядків
1+[0].toString() = 10
===а не =>?
Далі адаптується публікація в блозі, що відповідає на це запитання, яке я опублікував, поки це питання все ще було закрито. Посилання на (HTML-копію) специфікації ECMAScript 3, як і раніше, є базовою лінією JavaScript у поширених сьогодні веб-браузерах.
По-перше, коментар: подібний вираз ніколи не з’явиться в будь-якому (розумному) виробничому середовищі і є корисним лише для того, наскільки читач знає брудні краї JavaScript. Загальний принцип, згідно з яким оператори JavaScript неявно перетворюють між типами, є корисним, як і деякі звичайні перетворення, але значна частина деталей у цьому випадку не є.
Вираз ++[[]][+[]]+[+[]]може спочатку виглядати досить нав'язуючим і незрозумілим, але насправді досить легко розбити на окремі вирази. Нижче я просто додав дужки для чіткості; Можу запевнити, що вони нічого не змінюють, але якщо ви хочете перевірити це, тоді не соромтеся прочитати інформацію про оператора групування . Отже, вираз можна чіткіше записати як
( ++[[]][+[]] ) + ( [+[]] )
Розбиваючи це, ми можемо спростити, спостерігаючи, що +[]оцінюється до 0. Для того, щоб задовольнити себе , чому це так, перевірте унарний оператор + і слідувати злегка звивистому сліду , який закінчується з ToPrimitive перетворення порожнього масиву в порожній рядок, яка потім , нарешті , перетворюється в 0по ToNumber . Тепер ми можемо замінити 0кожен примірник +[]:
( ++[[]][0] ) + [0]
Простіше вже. Що стосується ++[[]][0], це комбінація оператора збільшення префікса ( ++), літералу масиву, що визначає масив з єдиним елементом, який сам є порожнім масивом ( [[]]), і властивість accessor ( [0]), що викликається в масиві, визначеному літералом масиву.
Отже, ми можемо спростити [[]][0]справедливе []і маємо ++[], правда? Насправді це не так, оскільки оцінювання ++[]кидає помилку, яка спочатку може здатися заплутаною. Однак, невелика думка про природу ++пояснює це: він використовується для збільшення змінної (наприклад ++i) або властивості об'єкта (наприклад ++obj.count). Він не тільки оцінює значення, але і зберігає його десь. У випадку з ++[]новим значенням (де б воно не було) ніде не було, оскільки воно не має посилання на властивість об'єкта чи змінну для оновлення. Якщо говорити специфічно, це покривається внутрішньою операцією PutValue , яку викликає оператор збільшення префікса.
Тож що ++[[]][0]робити? Ну, за такою ж логікою, як +[]внутрішній масив перетворюється на 0це значення і збільшується, 1щоб дати нам остаточне значення 1. Значення властивості 0у зовнішньому масиві оновлюється до, 1а весь вираз оцінюється до 1.
Це залишає нас
1 + [0]
... що є простим використанням оператора додавання . Обидва операнди спочатку перетворюються на примітиви, і якщо будь-яке примітивне значення є рядком, виконується конкатенація рядків, інакше виконується числове додавання. [0]перетворюється в "0", тому використовується рядкове конкатенація, що виробляє "10".
Як остаточний бік, щось, що може бути не відразу зрозумілим, - це те, що переосмислення будь-якого з методів toString()чи valueOf()методів Array.prototypeзмінить результат виразу, оскільки обидва перевіряються та використовуються, якщо вони є, при перетворенні об'єкта в примітивне значення. Наприклад, наступне
Array.prototype.toString = function() {
return "foo";
};
++[[]][+[]]+[+[]]
... виробляє "NaNfoo". Чому це трапляється, залишається читачем як вправа ...
Давайте спростимо:
++[[]][+[]]+[+[]] = "10"
var a = [[]][+[]];
var b = [+[]];
// so a == [] and b == [0]
++a;
// then a == 1 and b is still that array [0]
// when you sum the var a and an array, it will sum b as a string just like that:
1 + "0" = "10"
Цей оцінюється так само, але трохи менше
+!![]+''+(+[])
так оцінюється до
+(true) + '' + (0)
1 + '' + 0
"10"
Отже, тепер ви це зробили, спробуйте це:
_=$=+[],++_+''+$
"10"
Мабуть, найкоротші можливі способи оцінити вираз на "10" без цифр:
+!+[] + [+[]] // "10"
-~[] + [+[]] // "10"
// ========== Пояснення =========== \\
+!+[]: +[]Перетворює в 0. !0перетворює на true. +trueперетворюється в 1.
-~[]= -(-1)що дорівнює 1
[+[]]: +[]Перетворює в 0. [0]це масив з одним елементом 0.
Тоді JS оцінює 1 + [0], таким чином, Number + Arrayвираз. Тоді специфікація ECMA працює: +оператор перетворює обидва операнди в рядок, викликаючи toString()/valueOf()функції з базового Objectпрототипу. Він функціонує як добавна функція, якщо обидва операнди виразу є лише числами. Хитрість полягає в тому, що масиви легко перетворюють свої елементи в об'єднане подання рядків.
Деякі приклади:
1 + {} // "1[object Object]"
1 + [] // "1"
1 + new Date() // "1Wed Jun 19 2013 12:13:25 GMT+0400 (Caucasus Standard Time)"
Є хороший виняток, що два Objectsдоповнення призводять до NaN:
[] + [] // ""
[1] + [2] // "12"
{} + {} // NaN
{a:1} + {b:2} // NaN
[1, {}] + [2, {}] // "1,[object Object]2,[object Object]"
+ '' або + [] оцінює 0.
++[[]][+[]]+[+[]] = 10
++[''][0] + [0] : First part is gives zeroth element of the array which is empty string
1+0
10[]це НЕ еквівалентно "". Спочатку елемент витягується, потім перетворюється ++.
Крок за кроком цього, +поверніть значення до числа, і якщо ви додасте до порожнього масиву +[]... як він порожній і дорівнює 0, воно буде
Отже, звідти, тепер подивіться на свій код, це ++[[]][+[]]+[+[]]...
І є плюс між ними ++[[]][+[]]+[+[]]
Таким чином, вони [+[]]повернуться, [0]оскільки вони мають порожній масив, який перетворюється на 0інший масив ...
Отже, як уявіть, перше значення - це двовимірний масив з одним масивом всередині ... тому [[]][+[]]буде рівним тому, [[]][0]що повернеться []...
І наприкінці ++конвертуйте його та збільште до 1...
Тож ви можете собі уявити, 1+ "0"буде "10"...
+[]кидає порожній масив , щоб0... потім витрачати вечір ...;)