Acum câteva luni am primit o scrisoare de la un prieten:
Subiect: Puteți să vă dezvăluiți și să-mi explicați această linie de cod?
Text: Conteaza-ma prost, dar ... Nu inteleg si voi fi recunoscator daca il explici in detaliu. Acesta este un detector de raze în 128 de caractere. Cred că e delicios.
index.html
Am observat că variabila k este doar o constantă, așa că am scos-o din linie și am redenumit întârzierea.
code.js
var întârziere = 64;
var remiză = «pentru (n + = 7, i = întârziere, P = 'p \ n.'; j- = 1 / întârziere; P + = P [i% 2 (i% 2 * j-j + n / întârziere? ^ j) 1: 2]) j = întârziere / i; p.innerHTML = P ";
var n = setInterval (tragere, întârziere);
În continuare, var draw a fost doar un șir care a fost executat ca o funcție de eval cu o periodicitate setInterval, deoarece setInterval poate lua ambele funcții și șiruri de caractere. Am mutat var draw la o funcție explicită, dar a păstrat șirul original pentru referință doar pentru caz.
var întârziere = 64;
var p = document.getElementById ("p"); // <—————
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
var = funcția () pentru (n + = 7, i = întârziere, P = 'p.n'; i = n / întârziere ^ j) 1. 2]) j = întârziere / i; p.innerHTML = P;
>
>;
var n = setInterval (tragere, întârziere);
Apoi am declarat variabilele i, p și j și le-am transferat la începutul funcției.
var întârziere = 64;
var p = document.getElementById ("p");
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
var draw = funcția () var i = întârziere; // <—————
var P = "p.n";
var j;
pentru (n + = 7; i> 0; P + = P [i% 2. (i% 2 * j - j + 1. 2]) j = întârziere / i; p.innerHTML = P;
i - = 1 / întârziere;
>
>;
var n = setInterval (tragere, întârziere);
Am descompus buclă și mi-a transformat-o într-o buclă. Dintre cele trei părți ale fostei rămas doar o parte din CHECK_EVERY_LOOP, și orice altceva (RUNS_ONCE_ON_INIT; DO_EVERY_LOOP) a suferit în afara buclei.
var întârziere = 64;
var p = document.getElementById ("p");
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
var draw = funcția () var i = întârziere;
var P = "p.n";
var j;
n + = 7;
în timp ce (i> 0) / <———————-
// Actualizați codul HTML
p.innerHTML = P;
j = întârziere / i;
i - = 1 / întârziere;
P + = P [i% 2. (i% 2 * j - j + n / întârziere ^ j) 1. 2];
>
>;
var n = setInterval (tragere, întârziere);
Aici am extins operatorul ternar (condiția .Dacă dacă este adevărat, face dacă este fals) în P + = P [i% 2. (i% 2 * j - j + 1. 2];
Această valoare (index) este folosită pentru a schimba șirul P, așa că vom apela indexul și vom transforma șirul în P + = P [index];
var întârziere = 64;
var p = document.getElementById ("p");
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
var draw = funcția () var i = întârziere;
var P = "p.n";
var j;
n + = 7;
în timp ce (i> 0) // Update HTML
p.innerHTML = P;
j = întârziere / i;
i - = 1 / întârziere;
indice index;
permite iIsOdd = (i% 2! = 0); // <—————
P + = P [index];
>
>;
var n = setInterval (tragere, întârziere);
M-am întins 1 din indexul de valoare = (i% 2 * j - j + n / delay ^ j) 1 în altă declarație if.
Iată o modalitate dificilă de a verifica paritatea rezultatului în paranteze, când 0 pentru o valoare uniformă și 1 pentru un număr impar. Este un operator AND bitwise. Funcționează astfel:
1 1 = 1
0 1 = 0
Deci, ceva 1 transformă "ceva" într-o reprezentare binară și, de asemenea, termină în fața unității numărul necesar de zerouri pentru a se potrivi cu dimensiunea "ceva" și returnează pur și simplu rezultatul AND al ultimului bit. De exemplu, 5 în format binar este egal cu 101, deci dacă aplicăm operația logică AND la unitate pe ea, obținem următoarele:
0 1 // 0 - randament egal 0
1 1 // 1 - întoarcere parțială 1
2 1 // 0 - randament egal 0
3 1 // 1 - întoarcere parțială 1
4 1 // 0 - randament egal 0
5 1 // 1 - întoarcere parțială 1
Rețineți că am redenumit și restul indexului la magie, deci codul cu extensia 1 va arata astfel:
var întârziere = 64;
var p = document.getElementById ("p");
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
var draw = funcția () var i = întârziere;
var P = "p.n";
var j;
n + = 7;
în timp ce (i> 0) // Update HTML
p.innerHTML = P;
j = întârziere / i;
i - = 1 / întârziere;
indice index;
permite iIsOdd = (i% 2! = 0);
P + = P [index];
>
>;
var n = setInterval (tragere, întârziere);
Apoi, am desfasurat P + = P [index]; în declarația comutator. In acest moment, a devenit clar că indicele poate lua doar una dintre cele trei valori - 0, 1 sau 2. Se înțelege de asemenea că P variabilă este întotdeauna inițializată cu valori var P = „P. N.“;, unde 0 indică p, 1 indică pe. și 2 puncte la n - un caracter de linie nouă
var întârziere = 64;
var p = document.getElementById ("p");
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
var draw = funcția () var i = întârziere;
var P = "p.n";
var j;
n + = 7;
în timp ce (i> 0) // Update HTML
p.innerHTML = P;
j = întârziere / i;
i - = 1 / întârziere;
indice index;
permite iIsOdd = (i% 2! = 0);
dacă (iIsOdd) lăsați magic = (i% 2 * j - j + n / delay ^ j);
da magicIsOdd = (magia% 2! = 0); // 1
dacă (magicIsOdd) / &1
indice = 1;
> alt index = 0;
>
> alt index = 2;
>
var n = setInterval (tragere, întârziere);
Am înțeles operatorul var n = setInterval (remiză, întârziere); Metoda setInterval returnează numere întregi începând cu una, mărind valoarea pentru fiecare apel. Acest întreg poate fi folosit pentru clearInterval (adică, pentru a anula). În cazul nostru, setInterval este numit o singură dată, iar variabila n este pur și simplu setată la 1.
De asemenea, am redenumit întârzierea la DELAY pentru a reaminti că este doar o constantă.
Și nu în ultimul rând, am pus paranteze în% i 2 * j - j + n / DELAY ^ j pentru a indica faptul că ^ (XOR logic) prioritate mai mică decât operatorii%, *, -, +, și /. Cu alte cuvinte, toate calculele de mai sus se efectuează mai întâi și numai atunci ^. Asta se dovedește (i% 2 * j - j + n / DELAY) ^ j).
Clarificare: Mi sa spus că am plasat în mod eronat p.innerHTML = P; // Actualizați codul HTML într-o buclă, așa că am eliminat-o de acolo.
const DELAY = 64; // aproximativ 15 cadre pe secundă 15 cadre pe secundă * 64 secunde = 960 de cadre
var n = 1;
var p = document.getElementById ("p");
// var draw = "pentru (n + = 7, i = întârziere, P = 'p. \ n'; i- = 1 / întârziere; /delay^j)1:2])j=delay/i;p.innerHTML=P »;
/ **
* Desenează o fotografie
* 128 caractere cu 32 caractere = 4096 de caractere în total
* /
var draw = funcția () var i = DELAY; 64
var P = "p.n"; // Prima linie, referință pentru caracterele de utilizat
var j;
j = DELAY / i;
i - = 1 / DELAY;
indice index;
permite iIsOdd = (i% 2! = 0);
dacă (iIsOdd) lăsați magic = ((i% 2 * j - j + n / DELAY) ^ j); // <——————
da magicIsOdd = (magia% 2! = 0); // 1
dacă (magicIsOdd) / &1
indice = 1;
> alt index = 0;
>
> alt index = 2;
>
setInterval (desen, 64);
Rezultatul final poate fi văzut aici.
Partea 2. Înțelegerea codului
Ce se întâmplă aici? Să ne dăm seama.
Inițial valoarea i este setată la 64 prin var i = DELAY;, atunci fiecare ciclu se reduce la 1/64 (0.015625) prin i - = 1 / DELAY;. Buclele continuă atâta timp cât este mai mare decât zero (în timp ce (i> 0)
Imaginea este alcătuită din 32 de linii, cu 128 de caractere în fiecare. În mod convenabil, 64 x 64 = 128 x 32 = 4096. Valoarea lui i poate fi chiar un (nui nu lasa iIsOdd = (i% 2 = 0);) dacă i este chiar număr strict. .. Astfel apar de 32 de ori, atunci când acesta este egal cu 64, 62, 60 și 32, etc. Aceste index ori ia indicele valoric 2 = 2, și se adaugă la linia newline: P + = «n»; // aka P [2]. Restul de 127 de caractere din șir vor fi p sau.
Dar când să instalați p, și când.
Ei bine, pentru început, știm exact ce să instalăm. dacă valoarea ciudată lasă magia = ((i% 2 * j - j + n / DELAY) ^ j); sau setați p dacă "magic" este egal.
var P = "p.n";
dacă (magicIsOdd) / &1
indice = 1; al doilea caracter în P.
> alt index = 0; // primul caracter în P - p
>
Dar când magia este uniformă și când cea ciudată? Aceasta este o întrebare de un milion de dolari. Înainte de a trece la ea, să definim încă un lucru.
Dacă ștergeți + n / DELAY, lăsați magic = ((i% 2 * j - j + n / DELAY) ^ j), atunci obțineți o imagine statică care nu se mișcă deloc:
![Реверс-инжиниринг одной строчки javascript перевод, новостной постовой («for delay delay delay^j) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-e1f7e5ed.png)
Acum, uita-te la magie fără + n / DELAY. Cum a apărut această imagine frumoasă?
(i% 2 * j - j) ^ j
Acordați atenție la ceea ce se întâmplă în fiecare ciclu:
j = DELAY / i;
i - = 1 / DELAY;
Cu alte cuvinte, putem exprima j în termenii unui i finit ca j = DELAY / (i + 1 / DELAY). Dar din moment ce 1 / DELAY este prea mic, pentru acest exemplu, puteți să scădeți + 1 / DELAY și să simplificați expresia la j = DELAY / i = 64 / i.
În acest caz, putem rescrie (i% 2 * j - j) ^ j ca i% 2 * 64 / i - 64 / i) ^ 64 / i.
Utilizăm un calculator de grafică online pentru a desena diagrame ale unora dintre aceste funcții.
Mai întâi, atrage i% 2.
Se pare o diagramă frumoasă cu valori y de la 0 la 2.
Dacă desenați 64 / i, avem următorul grafic:
![Реверс-инжиниринг одной строчки javascript перевод, новостной постовой («for delay delay delay^j) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-f0c7c702.png)
Dacă desenați întreaga stângă a expresiei, veți obține un grafic care arată ca o combinație a celor două.
![Inversarea ingineriei unei traduceri pe linie de javascript, linia de știri (linie) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-3e8e5ca7.png)
În final, dacă desenăm două funcții una lângă cealaltă, vedem următoarele.
![Inversarea ingineriei unei traduceri pe linie de javascript, linia de știri (linie) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-28ef09c5.png)
Ce spun aceste grafice?
Să ne amintim întrebarea la care încercăm să răspundem, adică cum a surprins această imagine statică frumoasă:
![Inversarea inversă a unei traduceri javascript de o linie, releu de știri («pentru întârziere de întârziere) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-e1f7e5ed.png)
Știm că dacă "magia" (i% 2 * j - j) ^ j are o valoare uniformă, atunci adăugați p și adăugați pentru un număr impar.
Să creștem primele 16 linii ale graficului nostru, unde am valori de la 64 la 32.
![Реверс-инжиниринг одной строчки javascript перевод, новостной постовой («for delay delay delay^j) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-7528609f.png)
Returnează 0 dacă ambii biți sunt 1 sau ambii sunt 0.
j noastră pornește de la una și se deplasează încet la egalitate de puncte, oprindu-se chiar lângă el, astfel încât să putem presupune că este întotdeauna unitatea în timp ce rotunjirea în jos (Math.floor (1.9999) === 1), și avem nevoie de mai mult de un articol de pe partea stângă pentru a obține rezultatul zero și a ne da p.
Cu alte cuvinte, fiecare diagonală verde reprezintă un rând în graficul nostru. Deoarece pentru primele 16 de rânduri de valoarea j este întotdeauna mai mare decât 1, dar mai puțin de 2, atunci putem obține valoarea ciudat numai în cazul în care partea stângă a expresiei (i% 2 * j - j) ^ j, acesta este i% 2 * I / 64 - i / 64, adică diagonala verde, va fi, de asemenea, mai mare de 1 sau mai mică -1.
1 ^ 1 0 - chiar p
1.1 ^ 1.1 // 0 - chiar p
0,9 ^ 1 // 1 - impar.
0 ^ 1 // 1 - impar.
-1 ^ 1 / -2 - chiar p
-1,1 ^ 1,1 // -2 - chiar p
Dacă ne uităm la graficul nostru, atunci linia diagonală cea mai din dreapta părăsește abia peste 1 și mai jos -1 (puține numere chiar și câteva simboluri p). Următorul se duce puțin mai departe de aceste limite, cel de-al treilea - chiar și puțin mai departe etc. Numărul liniei 16 abia se află în limitele între 2 și -2. După linia 16, vedem că graficul nostru static își schimbă caracterul.
![Реверс-инжиниринг одной строчки javascript перевод, новостной постовой («for delay delay delay^j) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-c7d03598.png)
După linia 16, valoarea lui j intersectează limita 2, astfel încât rezultatul așteptat se modifică. Acum obținem un număr par, dacă linia diagonală verde este mai mare de 2 sau mai mică -2, sau în cadrul cadrelor 1 și -1, dar nu le atinge. De aceea vedem două sau mai multe grupuri de p simboluri în imagine începând cu linia a 17-a.
Dacă vă uitați la cele câteva linii inferioare din imaginea animată, veți observa că ele nu urmează același model datorită fluctuației mari din grafic.
Acum, reveniți la + n / DELAY. În cod, vedem că valoarea lui n începe cu 8 (1 de la setInteval și plus 7 pentru fiecare apel de metodă). Apoi se incrementează cu 7 de fiecare dată când setInteval este declanșat.
După atingerea valorii de 64, graficul se modifică după cum urmează.
![Inversarea ingineriei unei traduceri pe linie de javascript, linia de știri (linie) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-5ab5400c.png)
Rețineți că j este încă unul, dar acum jumătatea stângă a diagonalei roșii în intervalul de aproximativ 62-63 este de aproximativ zero, iar jumătatea dreaptă în jurul valorii de 63-64 este de aproximativ unu. Așa cum caracterele apar în ordine descrescătoare 64 - 62, se poate aștepta ca jumătatea din dreapta a diagonalei în regiunea 63-64 (1 ^ 1 = 0 // chiar) se adaugă p caractere teanc și jumătatea stângă a diagonalei în regiunea 62-63 ( 1 ^ 0 = 1 // ciudat) va adăuga o grămadă de puncte. Toate acestea vor crește de la stânga la dreapta, ca un text simplu.
![Inversarea ingineriei unei traduceri javascript dintr-o linie, linie de știri (javascript) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-cd30f86d.png)
În acest timp, numărul de simboluri p a crescut la o valoare constantă. De exemplu, în primul rând, jumătate din toate valorile vor fi întotdeauna egale. Acum simbolurile p și. va schimba locurile.
De exemplu, când n este incrementat cu 7 la următorul apel setInterval, graficul se schimbă ușor.
![Inversarea inversă a unei traduceri javascript de o linie, releu de știri («pentru întârziere de întârziere) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-2830970d.png)
Rețineți că diagonala pentru primul rând (aproape de marcajul 64) sa mutat cu aproximativ un mic pătrat în sus. Deoarece cele patru pătrate mari sunt de 128 de caractere, într-un pătrat mare vor fi 32 de simboluri și într-un mic pătrat 32/5 = 6,4 sivoli (aproximativ). Dacă ne uităm la redarea HTML, atunci primul rând a fost într-adevăr mutat spre dreapta pentru 7 caractere.
![Inversarea ingineriei unei traduceri pe linie de javascript, linia de știri (linie) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-0464a142.png)
Și un ultim exemplu. Iată ce se întâmplă dacă sunați setInterval șapte ori mai mult și n va fi 64 + 9 × 7.
![Реверс-инжиниринг одной строчки javascript перевод, новостной постовой («for delay delay delay^j) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-b787057a.png)
Pentru primul rând, j este încă 1. Acum, jumătatea superioară a diagonalei roșii lângă semnul 64 este de aproximativ două și capătul inferior este aproximativ unu. Aceasta inversează imaginea într-o altă direcție, pentru că acum 1 ^ 2 = 3 // ciudat -. și 1 ^ 1 = 0 // egal - p. Deci, vă puteți aștepta la multe puncte, urmate de simbolurile p.
Va arăta așa.
![Inversarea inversă a unei traduceri javascript de o linie, releu de știri («pentru întârziere de întârziere) Inversarea ingineriei unei traduceri javascript de o linie, post de știri](https://images-on-off.com/images/182/reversinzhiniringodnoystrochkijavascript-3836c18e.png)
Graficul este fixat fără sfârșit.
Sper că munca noastră are un sens. Este puțin probabil să fiu eu vreodată așa ceva, dar a fost interesant să înțeleg acest cod.