написал всё в пунктиках :
рассмотрим return поподробней, в нескольких частях
- ARR
return *!*[,,~0.[0|0] ]*/!* [ ... ] << ...;
создаст массив с длиной 3, где первый (key==0) и второй (key==1) равны undefined, а последний равен -1. почему ? краткая схема должна показать ход тождественных преобразований
~0.[0|0] => ~0.[0] => ~undefined => -1
убедитесь сами. причём разложение побитового "НЕ" (~) на тождественную ему математическую операцию ( ~a == -1*(a+1) ) не даст такого же результата, потому что любые арифметические операции (сложение, деление...) с undefined дают NaN :
alert( ~undefined == -1*(undefined+1) ); // false
итак. наш массив таков :
[ undefined, undefined, -1 ]
идём дальше.
- key
pewpew.__proto__.length && Infinity, -~String(*!*undefined||??*/!*).length >> __proto__
(подчёркнуто то, что неоднозначно : если в текущей области видимости есть переменная pewpew, то будет что-то отличное от undefined)
... ну да ладно. посчитаем, что ничего не определялось до запуска функции.
его формат :
Код:
|
NUM && undefined, NUM >> 2 |
значения аргументов подставлены из apply. там ещё length равен undefined - по аналогии с верхним пунктом.
... преобразовывается формат в такой (следуем по запятой - она просто возвратит значение справа)
т.е. в виде кода это :
pewpew.__proto__.length && undefined, -~String(undefined).length >> 2
обернём в скобки, чтобы пояснить, что операторы в JS работают слева направо :
( (NUM&&undefined), NUM) >> NUM
а теперь разбираем:
pewpew будет указывать на текущую функцию (arguments.callee). её свойство __proto__ равно пустой функции Empty.
вот тут я почесал репу. я знаю, почему, но не могу объяснить. это вторая стадия понимания (первая - "не понял").. плохо. буду читать
ну да ладно.
т.е.
pewpew.__proto__.toString() == "function Empty(){}"
у этой функции мы получаем количество аргументов length. само собой, оно равно нулю - 0
т.е. конструкция превращается в такую
(pewpew.__proto__.length, -~String(undefined).length) >> 2
>> будет работать с результатом запятой.
результат запятой- то, что находится с правой её стороны.
код превращается в такой :
-~String(undefined).length >> 2
этот код приведёт undefined к строке ("undefined", само собой)
далее он получит её длину (9), далее (от ~) прибавит к ней 1, умножит на -1 и (от -) поставит противоположный знак.
получаем
10 >> 2
это равно
alert( 10 >> 2 ); // 2
идём дальше.
- <<NUM
(0. === .0) + Infinity
то, что в скобках - разная форма записи одного и того же числа. разумеется, результат выполнения равен true :
Код:
|
0. => 0 }
| => 0 === 0 => true
.0 => 0 } |
далее идёт суммирования булевого true, который при приведении к числу становится 1 с undefined (аргумент)
это равно NaN :
Код:
|
(true + undefined) === NaN |
всё.
таким образом, форма записи этой функции расширяется до :
(убрал запятую и &&.)
(function pewpew(Infinity, length, __proto__){
return [undefined, undefined, -1][ -~String(undefined).length >> 2 ] << NaN;
}).call(typeof pewpew, undefined, undefined, 2);
...проверим, равны ли возвращаемые значения этого кода и оригинального ?
var original = (function pewpew(Infinity, length, __proto__) {
return [,,~0.[0|0]][pewpew.__proto__.length && Infinity, -~String(this).length >> __proto__] << (0. === .0) + Infinity;
}).apply(typeof pewpew, [,,2]);
var remixed = (function pewpew(Infinity, length, __proto__){
return [undefined, undefined, -1][ -~String(undefined).length >> 2 ] << NaN;
}).call(typeof pewpew, undefined, undefined, 2);
alert( original === remixed );
да. всё хорошо
если подставить переменные, то получается (без return. это уже не функция. просто код) :
[undefined, undefined, -1][2] << NaN
это эквивалентно :
-1 << NaN
и равно это
alert( -1 << NaN ); // -1
THE END