JavaScript bị xáo trộn này hoạt động như thế nào?


93

JavaScript sau hoạt động như thế nào?

Tôi hiểu rằng đó là mã được rút gọn. Tôi đã thử khử nhiễu nó một chút, nhưng tôi không thể có khái niệm rõ ràng về cách nó đạt được hiệu ứng này. Tôi có thể thấy rằng nó đang sử dụng Chuỗi để lặp lại một số loại, sử dụng đối tượng Ngày, thao tác chuỗi kỳ lạ, các hàm Toán học, sau đó mã tự in.

Làm thế nào mà hiệu ứng tương tự có thể được viết lại với một ví dụ tối thiểu?

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  A@ , */+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


8
Hoạt ảnh tuyệt vời ... có thể kết thúc bằng cách sử dụng nó ở đâu đó thực sự!
tymeJV

7
Ồ, tốt. Không nhận thấy sự khó khăn.
ThiefMaster

37
Đây được gọi là Quine, và đây là một trong những Quine tuyệt vời hơn mà tôi từng thấy. en.wikipedia.org/wiki/Quine_(computing)
David Souther

9
@Roko C. Buljan tôi nghĩ rằng đây là trang của mình: aem1k.com
Alexander

5
Có vẻ như tác giả hiện đã đưa lên GitHub một phiên bản có chú thích .
Der Hochstapler,

Câu trả lời:


67

Lời nói đầu : Tôi đã làm đẹp và chú thích mã rộng rãi tại http://jsfiddle.net/WZXYr/2/

Xem xét lớp ngoài cùng:

eval(z = '...');

Một chuỗi mã được lưu trữ trong biến z. Toán tử gán trả về giá trị được gán, vì vậy chuỗi mã cũng được chuyển như một đối số vào eval.

Chuỗi mã zchạy bên trong của eval. Mã cực kỳ khó hiểu, ngay cả khi được làm sạch, nhưng có vẻ như:

  1. Phân tích cú pháp một chuỗi các số cơ sở-36, được mô tả bằng ký tự 4.
  2. Cư bản đồ về giá trị, sử dụng các biến toàn cầu e, xytrạng thái bản đồ giữ. Trạng thái bản đồ một phần là chức năng của giây hiện tại trên đồng hồ treo tường (new Date / 1e3 ).
  3. Sử dụng các giá trị bản đồ, mã tạo ra một chuỗi đầu ra, p
    • mã sử dụng p += " *#"[index]để quyết định xem nên sử dụng dấu cách, dấu hoa thị hay dấu thăng, indexthực sự ở đâu e[x++] + e[x++](như đã nói ở trên exchịu trách nhiệm về trạng thái bản đồ)
    • nếu chỉ mục lớn hơn độ dài của " *#", sẽ có mã dự phòng điền đầu ra pvới các ký tự từ z. Các ký tự bên trong được điền với các ký tự hoạt hình, trong khi các ký tự bên ngoài được lấy từ z.

Ở cuối đoạn mã, có một lệnh gọi đến setTimeout(z), nó đánh giá chuỗi mã một cách không đồng bộ z. Lời gọi lặp lại này zcho phép mã lặp lại.

Ví dụ đơn giản:

Đây là một phiên bản siêu đơn giản ( 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)')
  1. Các forvòng lặp cho biết thêm mỗi nhân vật vào chuỗi sản lượng p(chuỗi là 172 ký tự):

    for(i=0;i<172;++i)
  2. Điều kiện bên trong quyết định nếu chúng ta đang ở một nhân vật từ vị trí 62 đến 67, đó là các nhân vật hoạt hình:

    if(i > 62 && i < 67)
  3. Nếu là chúng ta, thì hãy in ra !---, được dịch chuyển dựa trên phần mười của giá trị đồng hồ treo tường thứ hai. Điều này cung cấp hiệu ứng hoạt hình.

    p+="!---"[~~(new Date/1e2 + i)%4]

    (Tất cả những điều tồi tệ xung quanh new Datethực sự chỉ ở đó để chuyển đổi giá trị ngày tháng thành một số từ 0 đến 3)

  4. Ngược lại, nếu chúng ta không ở trên một ký tự hoạt hình, thì hãy in iký tự index- từ chuỗi được xác định bởi

    "eval(z='" + z + "')"

    Đó là, chuỗi mã được zbao quanh bởi eval('').

  5. Cuối cùng, xuất chuỗi và sử dụng setTimeoutđể xếp hàng đợi một thực thi khác của z:

    document.body.innerHTML = p;setTimeout(z)

Lưu ý rằng kết quả cuối cùng của tôi không hoàn toàn đúng - tôi chưa tính đến các dấu gạch chéo ngược ở cuối - nhưng nó vẫn sẽ cung cấp cho bạn một ý tưởng khá tốt về cách kỹ thuật hoạt động nói chung.


8
Lưu ý github.com/aemkei/world/blob/master/annotated.js này - phiên bản có chú thích của chính tác giả trong GitHub.
Benjamin Gruenbaum 23/09/13

36

Đây là nguồn được chú thích. Ps: Tôi là tác giả;)

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()

5
Lưu ý, nó cũng được giải thích trong video này youtube.com/watch?v=RTxtiLp1C8Y
Benjamin Gruenbaum

21

Đây là một phiên bản khác được giải mã theo cách thủ công, chuyển tất cả khởi tạo ra khỏi biểu thức thành các câu lệnh riêng:

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  A@ , */+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)

Đây là những gì sẽ xảy ra:

  • zlà một chuỗi nhiều dòng chứa tất cả mã. Nó làeval ed.
  • Vào cuối mã, zđược chuyển đến setTimeout. Nó hoạt động giống nhau requestAnimationFrameevalcùng nhau, đánh giá nó trong một khoảng thời gian với tỷ lệ cao nhất có thể.
  • Bản thân mã khởi tạo p, bộ đệm chuỗi mà HTML sẽ được thêm vào và n, một mảng các số được mã hóa cơ sở 36 (được nối thành một chuỗi bởi "4", các nhận xét là rác không liên quan không được xem xét parseInt).
  • mỗi số trong nmã hóa một dòng ( n.length == 16). Nó bây giờ được liệt kê .
  • Một loạt các biến được khởi tạo, một số biến được ngụy trang dưới dạng eký tự mảng nhưng sau đó chúng được chuyển thành số ( x) hoặc booleans ( r) hoặc chuỗi (t ) khi được sử dụng.
  • Mỗi chữ số trong số tđược liệt kê, đảo ngược boolean rmỗi lượt. Đối với các góc khác nhau xvà tùy thuộc vào thời điểm hiện tại new Date / 1000 (để nó tạo ra hình ảnh động), mảng eđược lấp đầy bằng cách sử dụng một số toán tử bitwise - với 1khi nào rlà sai và 2s khi nào rlà đúng tại thời điểm đó.
  • Sau đó, một vòng lặp lặp lại 61 cột của hình ảnh, từ x=0đến 122 trong các bước kép, thêm các ký tự đơn vào p.
  • Blà dấu gạch chéo ngược, chuỗi Sđược xây dựng từ chuỗi mã zbằng cách thoát khỏi dấu gạch chéo ngược và dấu nháy đơn, để có được sự trình bày chính xác về những gì nó trông trong nguồn.
  • Mỗi hai số liên tiếp từ eđược thêm vào và được sử dụng để truy cập một ký tự từ đó " *#", để xây dựng hình ảnh động. Nếu một trong các chỉ số không được xác định, NaNchỉ mục sẽ giải quyết thành một ký tự không xác định và thay vào đó, ký tự tương ứng từ Schuỗi được lấy (kiểm tra công thức x/2+61*y-1). Nếu ký tự đó phải là một ký tự từ , nó sẽ được tô màu khác bằng cách sử dụng fontcolorphương thức Chuỗi .
  • Sau mỗi dòng, khoảng trắng sau cùng và dấu ngắt dòng được thêm vào pvà chuỗi HTML được gán cho nội dung tài liệu.

Làm thế nào hiệu ứng tương tự có thể được viết lại cho một ví dụ tối thiểu?

Đây là một ví dụ khác:

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)')

( demo tại jsfiddle.net )

Nó có tất cả những thứ liên quan mà bạn cần cho loại hoạt hình này:

  • setIntervalDatecho hoạt hình
  • Một bản tái tạo mã của chính nó ( giống như quine ), ở đây:

    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
  • Đầu ra thông qua document.body.innerHTMLvà một <pre>phần tử

  • Thay thế một số phần của mã bằng chuỗi động

2
phải thừa nhận, câu trả lời tuyệt vời!
rafaelcastrocouto 20/09/13

5

Một chuỗi với tất cả mã được đánh giá và thời gian chờ tạo ra vòng lặp; Chuỗi được lưu trữ trong một biến có tên zvà ở giữa mã, giữa các bình luận /**/có một "Earth ASCII Art". Mã phân tích cú pháp các nhận xét và thay đổi nội dung tài liệu, giữ nguyên j và cập nhật nghệ thuật. Dưới đây chỉ là đoạn mã:

  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
  }

6
Dù sao đi nữa, thật khó tin khi xung quanh Xích đạo, đồ họa có nhiều vòng quay hơn ... tuyệt vời. +1 BTW
Roko C. Buljan,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.