Как этот запущенный JavaScript работает?
Как работает следующий JavaScript?
Я понимаю, что это минитипированный код, но я попытался немного скрыть его, но я не могу получить четкое представление о том, как он достигает этого эффекта. Я вижу, что он использует Strings для какой-то итерации, использования объекта Date, странной манипуляции строк, математических функций, затем код печатает сам.
Как можно переписать тот же эффект с минимальным примером?
eval(z='p="<"+"pre>"/* ,.oq#+ ,._, */;for(y in n="zw24l6k\
4e3t4jnt4qj24xh2 x/* =<,m#F^ A W###q. */42kty24wrt413n243n\
9h243pdxt41csb yz/* #K q##H######Am */43iyb6k43pk7243nm\
r24".split(4)){/* dP cpq#q##########b, */for(a in t=pars\
eInt(n[y],36)+/* p##@###YG=[#######y */(e=x=r=[]))for\
(r=!r,i=0;t[a/* d#qg `*PWo##q#######D */]>i;i+=.05)wi\
th(Math)x-= /* aem1k.com Q###KWR#### W[ */.05,0>cos(o=\
new Date/1e3/* .Q#########Md#.###OP [email protected] , */+x/PI)&&(e[~\
~(32*sin(o)*/* , (W#####Xx######.P^ T % */sin(.5+y/7))\
+60] =-~ r);/* #y `^TqW####P###BP */for(x=0;122>\
x;)p+=" *#"/* b. OQ####x#K */[e[x++]+e[x++\
]]||(S=("eval"/* l `X#####D , */+"(z=\'"+z.spl\
it(B = "\\\\")./* G####B" # */join(B+B).split\
(Q="\'").join(B+Q/* VQBP` */)+Q+")//m1k")[x/2\
+61*y-1]).fontcolor/* TP */(/\\w/.test(S)&&"#\
03B");document.body.innerHTML=p+=B+"\\n"}setTimeout(z)')//
JSFiddle
Ответы
Ответ 1
Предисловие: я украсил и подробно разместил код в http://jsfiddle.net/WZXYr/2/
Рассмотрим внешний слой:
eval(z = '...');
Кодовая строка сохраняется в переменной z
. Оператор присваивания возвращает назначенное значение, поэтому строка кода также передается в качестве аргумента в eval
.
Строка кода z
выполняется внутри eval
. Код очень тупой, даже если он очищен, но он выглядит следующим образом:
- Разбор строки из базовых чисел 36, обозначенной символом
4
.
- Заполните карту значений, используя глобальные переменные
e
, x
и y
, чтобы сохранить состояние карты. Состояние карты, частично, является функцией текущей секунды на настенных часах (new Date / 1e3
).
- Используя значения карты, код генерирует строку вывода,
p
- в коде используется
p += " *#"[index]
, чтобы решить, использовать ли пробел, звездочку или хеш-метку, где index
на самом деле e[x++] + e[x++]
(как сказано выше, e
и x
отвечают за состояние карты)
- если индекс больше длины
" *#"
, существует код возврата, который заполняет вывод p
символами из z
. Внутренние символы заполняются символами анимации, а внешние символы вытягиваются из z
.
В конце кода есть вызов setTimeout(z)
, который асинхронно оценивает строку кода z
. Этот повторный вызов z
позволяет кодировать код.
Простой пример:
Здесь супер-простая версия (http://jsfiddle.net/5QXn8/):
eval(z='p="<"+"pre>";for(i=0;i<172;++i)if(i > 62 && i < 67)p+="!---"[~~(new Date/1e2 + i)%4];else p += ("eval(z=\'" + z + "\')")[i];document.body.innerHTML = p;setTimeout(z)')
-
Цикл for
добавляет каждый символ к выходной строке p
(строка длиной 172 символа):
for(i=0;i<172;++i)
-
Внутреннее условие принимает решение, если мы находимся на символе между позициями 62-67, которые являются анимированными символами:
if(i > 62 && i < 67)
-
Если мы находимся, распечатайте !---
, сдвинувшись на десятую часть второго значения настенных часов. Это обеспечивает эффект анимации.
p+="!---"[~~(new Date/1e2 + i)%4]
(Вся гадость вокруг new Date
действительно существует, чтобы преобразовать значение даты в число от 0 до 3.)
-
В противном случае, если мы не на анимированном символе, напечатаем символ index- i
из строки, определенной
"eval(z='" + z + "')"
То есть, строка кода z
окружена eval('
и ')
.
-
Наконец, выведите строку и используйте setTimeout
для очередного выполнения z
:
document.body.innerHTML = p;setTimeout(z)
Обратите внимание, что мой окончательный результат не совсем прав - я не учитывал обратную косую черту ближе к концу - но он все равно должен дать вам довольно хорошее представление о том, как эта техника работает в целом.
Ответ 2
Вот аннотированный источник. Ps: Я автор;)
function z(){ // will be replaced with eval
p = "<" + "pre>"; // use <pre> tag for formatted output
for ( // loop though lines
y in n = ( // y - the line number
"zw24" + // n - the encoded data
"l6k4" + // every line holds encoded data
"e3t4" +
"jnt4" + // string will be concated in build process
"qj24" +
"xh2 4" + // data after spaces will be ignored but
"2kty24" + // … is used to not break block comments
"wrt4" + // … which will save some chars
"13n24" +
"3n9h24" +
"3pdxt4" +
"1csb 4" +
"3iyb6k4" +
"3pk724" +
"3nmr24"
).split(4) // data will be split by (unused) 4
){
for ( // loop throug every char in line
a in t = parseInt( // numbers are encoded as string
n[y], // … with a base of 36
36
) + ( // large number will be converted to string
e = // e - holds the rendered globe
x = // x - horizonal position
r = [] // r - bitmap flag if pixel is set
)
){
r = !r; // toggle binary flag
for ( // look though bitmap states
i = 0;
t[a] > i; // draw pixel t[a]-times
i += .05
)
with (Math) // refer to Math later
x -= .05,
0 > cos( // prevent backface visibility
o =
new Date / 1e3 + // get rotation based on current time
x / PI
) && (
e[ // access matrix
~~( // convert float to integer
sin(o) * // rotate around y axis
sin(.5 + y/7) *
32 // scale up the globe
) + 60 // move to center
] = -~r // store bitmap state in render matrix
)
}
for ( // loop through columns
x = 0;
122 > x; // break after char 122
) p += " *#"[ // add space, asterisk or hash
e[x++] + // … based pixel opacity
e[x++]
] || (S = ( // otherwise use the original code
"eval(z='" + // inception of missing "eval" statement
z
.split(B = "\\") // escape \ with \\
.join(B + B)
.split(Q = "'") // escape ' with \'
.join(B + Q) +
Q + // add missing ')
")////////" // add extra chars to fill mapping
)[
x / 2 + // get character at current position
61 * y-1
]
).fontcolor( // colorize outpu
/\w/.test(S) && // test for [0-9A-Z]
"#03B" // render blue
// otherwise pink (default)
);
document.body.innerHTML = // render output
p += // append new line
B + // add backspace
"\n"; // add new line
}
setTimeout(z) // render animation on next frame
}
z()
Ответ 3
Вот еще одна дебофисация вручную, перемещая всю инициализацию из выражения в собственные утверждения:
z='p="<"+"pre>"/* ,.oq#+ ,._, */;for(y in n="zw24l6k\
4e3t4jnt4qj24xh2 x/* =<,m#F^ A W###q. */42kty24wrt413n243n\
9h243pdxt41csb yz/* #K q##H######Am */43iyb6k43pk7243nm\
r24".split(4)){/* dP cpq#q##########b, */for(a in t=pars\
eInt(n[y],36)+/* p##@###YG=[#######y */(e=x=r=[]))for\
(r=!r,i=0;t[a/* d#qg `*PWo##q#######D */]>i;i+=.05)wi\
th(Math)x-= /* aem1k.com Q###KWR#### W[ */.05,0>cos(o=\
new Date/1e3/* .Q#########Md#.###OP [email protected] , */+x/PI)&&(e[~\
~(32*sin(o)*/* , (W#####Xx######.P^ T % */sin(.5+y/7))\
+60] =-~ r);/* #y `^TqW####P###BP */for(x=0;122>\
x;)p+=" *#"/* b. OQ####x#K */[e[x++]+e[x++\
]]||(S=("eval"/* l `X#####D , */+"(z=\'"+z.spl\
it(B = "\\\\")./* G####B" # */join(B+B).split\
(Q="\'").join(B+Q/* VQBP` */)+Q+")//m1k")[x/2\
+61*y-1]).fontcolor/* TP */(/\\w/.test(S)&&"#\
03B");document.body.innerHTML=p+=B+"\\n"}setTimeout(z)';
p = "<" + "pre>";
n = ["zw2", "l6k", "e3t", "jnt", "qj2", "xh2 x/* =<,m#F^ A W###q. */", "2kty2", "wrt", "13n2", "3n9h2", "3pdxt", "1csb yz/* #K q##H######Am */", "3iyb6k", "3pk72", "3nmr2", ""]
for (y in n) {
e = [];
x = 0;
r = true;
t = parseInt(n[y], 36) + "";
for (a in t) {
r = !r
for (i = 0; i < t[a]; i += 0.05) {
x -= 0.05;
o = new Date / 1e3 + x / Math.PI
if (Math.cos(o) < 0)
e[~~(32 * Math.sin(o) * Math.sin(0.5 + y / 7)) + 60] = -~r;
}
for (x = 0; x < 122;) {
S = "eval" + "(z='" + z.split(B = "\\").join(B + B).split(Q = "'").join(B + Q) + Q + ")//m1k"
p += " *#"[e[x++] + e[x++]] || S[x/2+61*y-1]).fontcolor(/\w/.test(S[x/2+61*y-1]) && "#03B");
}
p += B + "\n";
document.body.innerHTML = p;
}
setTimeout(z)
Вот что происходит:
-
z
- это многострочная строка, содержащая весь код. Это eval
ed.
- В конце кода
z
передается setTimeout
. Он работает как requestAnimationFrame
и eval
вместе, оценивая его в интервале с максимально возможной скоростью.
- Сам код инициализирует
p
, строковый буфер, на который будет добавлен HTML, и n
- массив чисел с кодировкой базы 36 (объединенный в строку с помощью "4"
, комментарии неактуальны мусор, который не рассматривается parseInt
).
- каждое число в
n
кодирует одну строку (n.length == 16
). Сейчас перечислены.
- Инициализируется куча переменных, некоторые из которых замаскированы как литерал массива
e
, но затем их переводят в числа (x
) или booleans (r
) или строки (t
) при использовании.
- Каждая цифра числа
t
перечислит, инвертируя логический r
каждый оборот. Для разных углов x
и в зависимости от текущее время new Date / 1000
(так что он дает анимацию), массив e
заполняется с помощью побитовых операторов - с 1
, когда r
является ложным и 2
, когда r
истинно в это время.
- Затем цикл выполняет итерацию 61 столбца изображения, от
x=0
до 122 в двух шагах, добавляя одиночные символы к p
.
-
B
, являющийся обратным слэшем, строка S
построена из строки кода z
путем эвакуации обратных косых черт и апострофов, чтобы получить точное представление о том, что она смотрела в источнике.
- Каждый два последовательных номера из
e
добавляются и используются для доступа к символу из " *#"
для создания анимированного изображения. Если один из индексов не определен, индекс NaN
разрешается символом undefined, и вместо этого выполняется соответствующий символ из строки S
(проверьте формулу x/2+61*y-1
). Если этот символ должен быть символом слова, он по-разному окрашивается с помощью fontcolor
Метод String.
- После каждой строки добавочное backspace и linebreak добавляются в
p
, а строка HTML присваивается телу документа.
Как можно было бы переписать один и тот же эффект для минимального примера?
Вот еще один пример:
setInterval(z='s=("setInterval(z=\'"+\
z.replace(/[\\\\\']/g,"\\\\$&")+"\')"\
).match(/.{1,37}/g).join("\\\\\\n");d\
ocument.body.innerHTML=\"<\\pre>"+s.s\
lice(0, 175)+String( + new Date()).fo\
ntcolor("red")+s.slice(188)')
(демонстрация на jsfiddle.net)
У этого есть все необходимые вещи для этой анимации:
-
setInterval
и Date
для анимации
-
Реконструкция собственного кода (quine-like), здесь:
s = ( "setInterval(z='" // the outer invokation
+ z.replace(/[\\\']/g,"\\$&") // the escaped version
+ "\')" ) // the end of the assignment
.match(/.{1,37}/g).join("\\\n"); // chunked into lines
-
Выход через document.body.innerHTML
и a <pre>
элемент
- Замена некоторых частей кода анимированной строкой
Ответ 4
Строка со всем кодом оценивается, и таймаут делает цикл;
Строка хранится в переменной с именем z
и в середине кода между комментариями /*
и */
появляется "Earth ASCII Art".
Код анализирует комментарии и изменяет содержимое документа, сохраняя js и обновляя искусство. Пыльник - это только что нарезанный код:
p="<pre>";
for(y in n="zw24l6k4e3t4jnt4qj24xh2 x42kty24wrt413n243n9h243pdxt41csb yz43iyb6k43pk7243nmr24".split(4)){
for(a in t = parseInt(n[y],36)+(e=x=r=[]))
for(r=!r,i=0;t[a]>i;i+=.05)
with(Math) x-= .05,0>cos(o=new Date/1e3+x/PI)&&(e[~~(32*sin(o)*sin(.5+y/7))+60] =-~ r);
for(x=0;122>x;) p += " *#"[e[x++]+e[x++\]] ||
(S=("eval"+"(z=\'"+z.split(B = "\\\\").join(B+B).split(Q="\'").join(B+Q)+Q+")//m1k")[x/2+61*y-1]).fontcolor(/\\w/.test(S)&&"#\03B");
p += B+"\\n"
document.body.innerHTML= p
}