Forțați ieșirea din buclă în javascript. Bucle JavaScript. Buclă infinită pentru

Cicluri sunt folosite pentru a executa o anumită secțiune de cod de mai multe ori la rând.

De ce este necesar acest lucru?- imaginați-vă că trebuie să pătrați 100 de elemente de matrice.

Dacă accesați fiecare element separat prin cheia sa, va fi nevoie de 100 de linii de cod, iar pentru a scrie acest cod, va trebui să petreceți destul de mult timp. Dar acest lucru nu este necesar - avem posibilitatea ca JavaScript să efectueze o operațiune pentru noi numărul necesar de ori

. De exemplu, am pătrat toate elementele unui tablou..

Acest lucru se face folosind

cicluri buclă while Ciclu in timp ce va fi executat până la

dreapta

(adevărat) expresia transmisă de parametru. buclă while Vezi sintaxa: While (în timp ce expresia este adevărată) (executăm acest cod ciclic; la începutul fiecărei bucle verificăm expresia în paranteze) /* Bucla se va termina când expresia nu mai este adevărată. Dacă inițial a fost fals, atunci nu va fi executat niciodată! */ Practic, un ciclu poate fi efectuată

la nesfârşit

(dar acest lucru va face ca scriptul să se blocheze!), transmiteți-i doar o expresie care< 5) { /* С помощью оператора ++ увеличиваем i на единицу при каждом проходе цикла. */ i++; alert(i); }

nu va deveni niciodată fals . De exemplu, așa: Să tipărim secvenţial numerele de la unu la cinci folosind o buclă while: Var i = 0; //contor de buclă while (i Observați variabila

i . De exemplu, așa:, - ea este așa-zisa contor de cicluri ..

Contoarele sunt folosite pentru a număra de câte ori a fost executată o buclă.

cicluri În plus, au un rol auxiliar - în sarcina noastră, am folosit un contor pentru a afișa numerele de la 1 la 5. Se obișnuiește să se folosească litere pentru contoare jȘi

k

pentru buclă pentru este.

alternativă la while - . Este mai greu de înțeles, dar este adesea iubit mai mult decât în ​​timp, deoarece ocupă mai puține rânduri. For (comenzi inițiale; condiție pentru încheierea buclei; comenzi după buclă) (corpul buclei) Comenzile inițiale

- asta se va executa inainte de inceperea ciclului. Vor fi executate o singură dată. De obicei, valorile inițiale ale contoarelor sunt plasate acolo, de exemplu:.

i = 0 În plus, au un rol auxiliar - în sarcina noastră, am folosit un contor pentru a afișa numerele de la 1 la 5. Condiția de sfârșit a buclei

/* La începutul buclei, i va fi egal cu zero, bucla va fi executată până la i< 10, после каждого прохода к i прибавляется единица: */ for (var i = 0; i < 10; i++) { alert(i); //выведет 0, 1, 2... 9 }

Ciclu fără corp

Puteți omite acolade în bucle - în acest caz, bucla va executa doar o linie sub ea (nu recomand să faceți acest lucru, adesea duce la erori):

Pentru (var i = 0; i< 10; i++) //<--- точки с запятой нет alert(i); //выведет 0, 1, 2... 9

Dar dacă după ) puneți un punct și virgulă - bucla se va închide și următoarea linie nu va intra în ea, veți obține o așa-numită buclă fără corp, care în cazul nostru va derula pur și simplu și, ca rezultat, va schimba valoarea variabilei . De exemplu, așa::

Pentru (var i = 0; i< 10; i++); //<--- точка с запятой есть alert(i); //выведет 9

Această buclă este uneori folosită, veți vedea exemple de utilizare atunci când analizați problemele în bucle.

Comenzi multiple într-o buclă for

Dacă trebuie să executăm mai multe comenzi între paranteze, le indicăm separate prin virgule:

Pentru (var i = 0, j = 2; i

Să ne uităm la bucla de mai sus: înainte ca bucla să treacă, vor fi executate două comenzi: var i = 0, j = 2(rețineți că var este scris aici o dată), iar după fiecare iterație - de trei ori: i++, j++, i = i + j.

Acest exemplu nu este deosebit de util din punct de vedere al programării, pur și simplu arată schematic că acest lucru se poate face.

Ține minte, îți va fi de folos în viitor.

bucla for pentru matrice În plus, au un rol auxiliar - în sarcina noastră, am folosit un contor pentru a afișa numerele de la 1 la 5. Folosind o buclă

<= arr.length-1; i++) { alert(arr[i]); //выведет 1, 2, 3, 4, 5 }

Puteți itera elementele unui tablou secvenţial. Acest lucru se face după cum urmează:

Punctul cheie este că repetăm ​​de la zero la lungimea matricei minus 1 (deoarece numărul ultimului element al matricei este cu unul mai mic decât lungimea sa). <= Nu trebuie să luați o unitate, ci un loc < :

do< arr.length; i++) { alert(arr[i]); //выведет 1, 2, 3, 4, 5 }

Var arr = ; pentru (var i = 0; i

bucla for-in Pentru a itera printr-un obiect, se folosește o așa-numită buclă. pentru-in

. Să vedem cum funcționează.

Să ni se dea următorul obiect:

Var obj = (Kolya: 200, Vasya: 300, Petya: 400); Să-i scoatem cheile. Pentru a face acest lucru, folosim următoarea construcție: pentru (cheie în obj) , Unde obj este obiectul pe care îl iterăm și cheie

- aceasta este o variabilă în care cheile obiectului vor fi stocate secvențial (numele său poate fi orice vă puteți gândi - asta va fi).

Adică, în această buclă nu este nevoie să specificați o condiție de sfârșit - se va itera peste cheile obiectului până când acestea se termină.

Deci, așa vom tipări toate cheile obiectului (una câte una):

Var obj = (Kolya: 200, Vasya: 300, Petya: 400); pentru (key in obj) ( alert(cheie); //va afișa „Kolya”, „Vasya”, „Petya” ) , Unde.

Dacă avem nevoie de valori în loc de chei, trebuie să ne accesăm obiectul prin cheie, astfel: este obiectul pe care îl iterăm și Cum funcționează: într-o variabilă , Unde mai întâi va fi „Kolya”, adică in acest caz nu conteaza obj[„Kolya”] este obiectul pe care îl iterăm și, data viitoare când bucla trece prin variabilă

Deci, să afișăm toate elementele obiectului:

Var obj = (Kolya: 200, Vasya: 300, Petya: 400); pentru (tastați obj) ( alert(obj); //va afișa 200, 300, 400 )

instrucțiuni de pauză

Uneori trebuie să încheiem bucla mai devreme în cazul unei bucle for, aceasta înseamnă înainte ca bucla să fi iterat prin toate elementele matricei.

De ce ar putea fi nevoie de acest lucru? De exemplu, ne confruntăm cu sarcina de a afișa elemente de matrice până când numărul 3 este întâlnit, bucla trebuie să-și finalizeze activitatea.

Acest lucru se poate face folosind instrucțiunile pauză- dacă execuția buclei ajunge la el, bucla își va încheia activitatea.

Să rezolvăm problema de mai sus - întrerupeți bucla de îndată ce întâlnim numărul 3:

do< arr.length; i++) { if (arr[i] === 3) { break; //выходим из цикла } else { alert(arr[i]); } }

Continuați instrucțiunile

Există și o instrucțiune continua, la atingerea căruia bucla începe o nouă iterație.

Uneori poate fi util pentru simplificarea codului, deși aproape întotdeauna problema poate fi rezolvată fără el.

Ce ar trebui să faci în continuare:

Începeți să rezolvați probleme folosind următorul link: probleme pentru lecție.

Când decideți totul, treceți la studiul unui subiect nou.

Scopul principal al JavaScript-ului while este de a rula în mod repetat o anumită bucată de cod, iar și iar. Este foarte asemănător cu o buclă for cu o diferență importantă. Permiteți-mi să-mi iau puțin din timp pentru a explica diferența dintre aceste două tipuri de cicluri.

Care este diferența dintre buclele while și for?

Diferența dintre aceste bucle este modul în care opresc executarea unei bucăți de cod.

Bucla for execută un număr stabilit de iterații. Știm exact de câte ori bucla va executa fragmentul de cod conținut în corpul său.

În timp, totul se întâmplă diferit. O buclă JavaScript while rulează atâta timp cât o anumită condiție este adevărată. Odată ce condiția devine falsă, atunci bucla while se termină.

Motivul pentru care aceste bucle sunt diferite este că nu putem ști neapărat în avans când o anumită condiție nu va mai fi adevărată. Prin urmare, nu putem prezice câte iterații ale buclei while se vor finaliza înainte de a se întrerupe.

Avantaje și dezavantaje ale buclei while

Permiteți-mi să încep prin a vedea singurul dezavantaj major al buclei while. Poate funcționa pentru totdeauna!

Ar trebui să rețin că bucla while negestionată de JavaScript, de obicei, nu rulează pentru totdeauna. Pentru că, în calitate de programatori, avem întotdeauna responsabilitatea de a ne asigura că la un moment dat starea buclei noastre while devine falsă.

Acum, în ceea ce privește „avantajele” - acestea sunt foarte evidente. While va rula continuu atâta timp cât condiția este îndeplinită. Un exemplu de utilizare a unei bucle while este acela de a cere utilizatorului să introducă date. Bucla vă va solicita să introduceți date din nou și din nou până când utilizatorul introduce datele corecte.

Sintaxa buclei while

Sintaxa buclelor for și while este foarte asemănătoare.

Trebuie să utilizați cuvântul cheie while și, de asemenea, să definiți condiția în care va fi executată bucla. Ca și alte structuri de control, bucla while își definește domeniul de aplicare.

Iată cum ar trebui să arate codul:

while () ( // introduceți aici codul care ar trebui să fie executat într-o buclă)

Cea mai grea parte este să determinați ce condiție sau condiții trebuie plasate în buclă pentru ca acesta să funcționeze corect.

Rețineți că atâta timp cât condiția este adevărată, bucla va continua să ruleze. Să ne uităm la un exemplu de utilizare în timp ce în JavaScript.

Exemplu de buclă while

Să presupunem că vrem să cerem utilizatorului să introducă un număr între 1 și 10. Dar ce se întâmplă dacă introduce un număr greșit?

În acest caz, trebuie să îi cerem să introducă din nou valoarea și să verificăm dacă condiția este îndeplinită ( dacă este introdus un număr de la 1 la 10).

Acesta este un caz în care o buclă for ar eșua lamentabil. Pentru că nu putem ști dinainte de câte ori va trebui să cerem utilizatorului să introducă numărul corect. În acest caz, bucla while ne vine în ajutor.

Iată cum ar putea arăta codul nostru:

var theNumber = prompt("Vă rugăm să introduceți un număr de la 1 la 10."); în timp ce (Numărul< 1 || theNumber >10 || isNaN(theNumber)) ( theNumber = prompt("Valoare introdusă nevalidă, introduceți un număr între 1 și 10!"); ) alert("Excelent! Ați introdus un număr: " + theNumber);

Este demn de remarcat faptul că în exemplul de mai sus avem trei condiții separate într-o buclă while JavaScript.

Acestea sunt cele trei condiții: numărul 10 || esteNaN(numărul). Ele indică următoarele:

  • DACĂNumărul este mai mic decât 1, SAU;
  • DACĂNumărul este mai mare decât 10, SAU;
  • DACĂ Numărul NU este un număr, atunci continuați bucla.

Deoarece folosim operatorul SAU (||) între toate condițiile, aceasta înseamnă că dacă oricare dintre condiții este adevărată, atunci condiția generală a buclei while va fi evaluată la adevărată și bucla va continua să se execute.

Numai dacă toate cele trei condiții sunt evaluate ca false, starea generală a buclei while va fi evaluată ca falsă și se va opri.

Concluzie

JavaScript while loop este singura buclă reală în limbajele de programare. for este doar o variație specială a buclei while.

Acesta este un caz în care puteți recrea singur o buclă for folosind sintaxa buclei while, urmăriți și învățați:

var counter = 0; în timp ce (contor< 10) { counter = counter + 1; console.log("The counter is currently at: " + counter); }

Codul va fi repetat de exact 10 ori, nici mai mult, nici mai puțin. Exact așa funcționează bucla for.

Ultima actualizare: 04/08/2018

Buclele vă permit să efectuați o acțiune de mai multe ori în funcție de anumite condiții. JavaScript are următoarele tipuri de bucle:

    pentru..in

    pentru..de

    buclă while

    face în timp ce

Contoarele sunt folosite pentru a număra de câte ori a fost executată o buclă.

Bucla for are următoarea definiție formală:

Pentru ([inițializarea contorului]; [condiția]; [modificarea contorului])( // acțiuni )

De exemplu, folosim o buclă for pentru a itera elementele unui tablou:

Oameni Var = ["Tom", "Alice", "Bob", "Sam"]; pentru(var i = 0; i

Prima parte a declarației buclei - var i = 0 - creează și inițializează contorul - variabila i. Și înainte ca bucla să se execute, valoarea acesteia va fi 0. În esență, aceasta este același lucru cu declararea unei variabile.

A doua parte este condiția în care va fi executată bucla. În acest caz, bucla va rula până când valoarea lui i atinge o valoare egală cu lungimea matricei people. Puteți obține lungimea unui tablou folosind proprietatea length: people.length .

A treia parte este creșterea contorului cu unul.

Și deoarece există 4 elemente în matrice, blocul buclă va rula de 4 ori până când valoarea lui i devine egală cu people.length (adică 4). Și de fiecare dată această valoare va crește cu 1. Fiecare repetare individuală a buclei se numește iterație. Astfel, în acest caz, vor funcționa 4 iterații.

Și folosind expresia people[i] putem obține un element de matrice pentru ieșirea ulterioară în browser.

Nu este necesar să măriți contorul cu unul, puteți efectua alte acțiuni cu acesta, de exemplu, micșorați-l cu una:

Oameni Var = ["Tom", "Alice", "Bob", "Sam"]; for(var i = people.length - 1; i >= 0; i--)( console.log(people[i]); )

În acest caz, matricea este scoasă de la sfârșit, iar matricea este iterată de la i = 3 la i = 0.

pentru..in

Bucla for..in este concepută pentru a itera prin matrice și obiecte. Definiția sa formală este:

Pentru (index în matrice) ( // acțiuni )

De exemplu, să repetăm ​​elementele matricei:

Oameni Var = ["Tom", "Alice", "Bob", "Sam"]; pentru(indexul var în oameni)( console.log(oameni); )

Buclă pentru...de

Bucla for...of este similară cu bucla for...in și este concepută pentru a itera prin colecții, cum ar fi matrice:

Permite utilizatorilor = [„Tom”, „Bob”, „Sam”]; for(lasa valul utilizatorilor) console.log(val);

Elementul de colecție curent care se repetă este plasat în variabila val, a cărei valoare este apoi imprimată pe consolă.

Acest lucru se face folosind

Bucla while rulează atâta timp cât o condiție este adevărată. Definiția sa formală este:

În timp ce(condiție)( // acțiuni )

Din nou, vom afișa elementele matricei folosind while:

Oameni Var = ["Tom", "Alice", "Bob", "Sam"]; var index = 0; în timp ce (index< people.length){ console.log(people); index++; }

Bucla while aici se va executa până când valoarea indexului este egală cu lungimea matricei.

face în timp ce

Într-o buclă do, codul buclei este mai întâi executat, iar apoi condiția din instrucțiunea while este verificată. Și atâta timp cât această condiție este adevărată, ciclul se repetă. De exemplu:

Var x = 1; do( console.log(x * x); x++; )while(x< 10)

Aici codul buclei va rula de 9 ori până când x devine 10. Bucla do garantează că acțiunea va fi executată cel puțin o dată, chiar dacă condiția din instrucțiunea while nu este adevărată.

Continuați și întrerupeți declarațiile

Uneori este necesar să părăsiți o buclă înainte de a se finaliza. În acest caz, putem folosi instrucțiunea break:

< array.length; i++) { if (array[i] >10) pauză;
"); }

document.write(matrice[i] + "

Această buclă iterează prin toate elementele matricei, dar ultimele patru elemente nu vor fi afișate în browser, deoarece testul if (array[i] > 10) va întrerupe execuția buclei folosind instrucțiunea break atunci când iterați prin matrice. ajunge la elementul 12.

Dacă trebuie doar să sărim iterația, dar nu să ieșim din buclă, putem folosi instrucțiunea continue:< array.length; i++) { if (array[i] >Var array = [ 1, 2, 3, 4, 5, 12, 17, 6, 7 ]; pentru (var i = 0; i
"); }

10) continua;

document.write(matrice[i] + "

Dacă nu acordați atenție conținutului textelor, atunci așa arată de obicei codul complex, ale cărui secțiuni arată ca literele „V” aflate pe o parte și codul simplu, al cărui bloc, dacă o faceți nu țin cont de diferitele lungimi ale liniilor, arată ca un dreptunghi.


Cu cât mai multe indentări, cu atât codul este de obicei mai complex.

Construcțiile care trebuie să fie indentate vor fi întotdeauna în cod, nu se vorbește despre a scăpa complet de ele. Totuși, avem puterea de a reduce complexitatea programelor pe care le scriem, alegând rațional abstracții pentru a rezolva problemele cu care ne confruntăm.

Să luăm matrice de exemplu. În mod tradițional, acestea sunt prelucrate folosind tipuri diferite cicluri. Conceptele de „matrice” și „buclă” sunt indisolubil legate în mintea multor programatori. Cu toate acestea, ciclul este o construcție foarte ambiguă. Iată ce scrie Louis Atenzio despre bucle în cartea sa Functional Programming in JavaScript: „O buclă este o buclă rigidă. structura de control, care nu este ușor de reutilizat și greu de integrat cu alte operațiuni. De asemenea, folosirea buclelor înseamnă crearea unui cod care se modifică cu fiecare iterație.”


Este posibil să scapi de cicluri?

Ciclul este una dintre principalele structuri structurale de control și, de fapt, nu vom spune că ciclurile sunt un rău de care trebuie scăpat. Scopul nostru principal este de a reduce complexitatea propriului cod prin minimizarea folosirii buclelor la procesarea matricelor. Este posibil? Vă invităm să aflați împreună.

Cicluri

Am vorbit deja despre modul în care constructele de control precum buclele adaugă complexitate codului tău. Dar de ce este așa? Să aruncăm o privire la modul în care funcționează buclele în JavaScript.

Există mai multe moduri de a organiza buclele în JS. În special, unul dintre tipurile de bază de bucle este while . Înainte de a pătrunde în detalii, să ne pregătim puțin. Și anume, vom crea o funcție și o matrice cu care vom lucra.

// oodlify:: String -> String function oodlify(s) ( return s.replace(//g, "oodle"); ) const input = [ "John", "Paul", "George", "Ringo", ];
Deci, avem o matrice, fiecare element al căruia îl vom procesa folosind funcția oodlify. Dacă utilizați o buclă while pentru a rezolva această problemă, veți obține următoarele:

Fie i = 0; const len ​​​​= input.length; lasa iesirea = ; in timp ce eu< len) { let item = input[i]; let newItem = oodlify(item); output.push(newItem); i = i + 1; }
Rețineți că folosim contorul i pentru a urmări elementul de matrice procesat în prezent. Acesta trebuie inițializat la zero și incrementat cu unul la fiecare iterație a buclei. În plus, trebuie să o comparați cu lungimea matricei, cu len, pentru a ști când să nu mai funcționeze.

Acest model este atât de comun încât JavaScript are o modalitate mai ușoară de a face acest lucru: o buclă for. O astfel de buclă va rezolva aceeași problemă după cum urmează:

Const len ​​​​= input.length; lasa iesirea = ; pentru (fie i = 0; i< len; i = i + 1) { let item = input[i]; let newItem = oodlify(item); output.push(newItem); }
Bucla for este o construcție utilă, deoarece pune toate operațiunile auxiliare standard de contor în partea de sus a blocului. Folosind while , este ușor să uiți de necesitatea de a crește contorul i , ceea ce va duce la o buclă infinită. Bucla for este cu siguranță mult mai convenabilă decât bucla while. Dar haideți să încetinim și să aruncăm o privire la ceea ce încearcă să obțină codul nostru. Dorim să procesăm, folosind funcția oodlify(), fiecare element al matricei și să punem rezultatul într-o matrice nouă. Contorul în sine, folosit pentru a accesa elementele matricei, nu ne interesează.

Acest model de lucru cu matrice, care implică efectuarea anumitor acțiuni asupra fiecărui element, este foarte comun. Drept urmare, ES2015 a introdus un nou design de buclă care vă permite să uitați de contor. Aceasta este o buclă for...of. Fiecare iterație a acestei bucle oferă următorul element al matricei. Arata cam asa:

Fie ieșire = ; pentru (lasă elementul de intrare) (let newItem = oodlify(element); output.push(newItem); )
Codul pare mult mai curat. Vă rugăm să rețineți că nu există nicio operație de contor sau de comparare. Cu această abordare, nici măcar nu este nevoie să accesați un anumit element de matrice prin index. Bucla for...of se ocupă de toate operațiunile auxiliare.

Dacă ne finalizam studiul despre modalitățile de a lucra cu matrice și de a folosi for...of bucle peste tot în loc de bucle for, acesta va fi deja un bun pas înainte prin simplificarea codului. Dar... putem merge mai departe.

Transformarea tablourilor

Bucla for...of pare mult mai curată decât bucla for, dar are și o mulțime de elemente auxiliare în cod. Deci, trebuie să inițializați matricea de ieșire și să apelați metoda push() în fiecare iterație a buclei. Codul poate fi făcut și mai compact și mai expresiv, dar înainte de a face asta, să extindem puțin problema demonstrației. Ce se întâmplă dacă trebuie să procesați două matrice folosind funcția oodlify()?

Const fellowship = [ „frodo”, „sam”, „gandalf”, „aragorn”, „boromir”, „legolas”, „gimli”, ]; const band = [ „John”, „Paul”, „George”, „Ringo”, ];
O soluție complet evidentă este să folosiți două bucle și să procesați matricele din ele:

Lasă bandoodle = ; pentru (lasă elementul benzii) (let newItem = oodlify(element); bandoodle.push(newItem); ) let floodleship = ; pentru (lasă elementul de părtășie) (let newItem = oodlify(element); floodleship.push(newItem); )
O variantă destul de funcțională. Și codul care funcționează este mult mai bun decât codul care nu rezolvă problema atribuită acestuia. Dar două bucăți de cod foarte asemănătoare nu se potrivesc foarte bine cu principiul de proiectare a software-ului DRY. Codul poate fi refactorizat pentru a reduce repetarea.

Urmând această idee, creăm următoarea funcție:

Funcția oodlifyArray(input) (let output = ; for (let item of input) (let newItem = oodlify(element); output.push(newItem); ) return output; ) let bandoodle = oodlifyArray(band); let floodleship = oodlifyArray(fellowship);
Acest lucru arată mult mai bine, dar ce se întâmplă dacă există o altă funcție cu care dorim să procesăm și elemente de matrice?

Funcția izzlify(s) ( return s.replace(/+/g, "izzle"); )
Acum funcția oodlifyArray() nu va ajuta. Totuși, dacă creăm o altă funcție similară, de data aceasta izzlufyArray() , ne vom repeta din nou. Totuși, să creăm o astfel de funcție și să o comparăm cu oodlifyArray() :

Funcția oodlifyArray(input) (let output = ; for (let item of input) (let newItem = oodlify(item); output.push(newItem); ) return output; ) function izzlifyArray(input) (let output = ; for ( lasă elementul de intrare) (let newItem = izzlify(element); output.push(newItem); ) return output )
Cele două funcții sunt incredibil de asemănătoare. Poate putem rezuma modelul pe care îl urmează? Scopul nostru este acesta: „Avem o matrice și o funcție. Trebuie să obținem o nouă matrice în care vor fi scrise rezultatele procesării fiecărui element din matricea originală folosind funcția.” Această metodă de procesare a tablourilor se numește „mapping” sau „transformation” (mapping în terminologia engleză). Funcțiile care efectuează astfel de operații sunt de obicei numite „hartă”. Iată cum arată versiunea noastră a unei astfel de funcții:

Harta funcției(f, a) (let output = ; for (let item of a) ( output.push(f(item)); ) return output; )
Deși bucla este acum o funcție separată, nu a fost posibil să scapi complet de ea. Dacă mergi până la capăt și încerci să te descurci complet fără constructe ciclice, poți scrie o versiune recursivă a aceluiași lucru:

Funcție map(f, a) ( dacă (a.lungime === 0) ( return ; ) return .concat(map(f, a.slice(1))); )
Soluția recursivă pare foarte elegantă. Doar câteva linii de cod și un minim de indentare. Dar implementările recursive ale algoritmilor sunt de obicei utilizate cu mare prudență și, de asemenea, suferă de performanță slabă în browserele mai vechi. Și, de fapt, nu trebuie să scriem o funcție pentru a implementa singuri operația de mapare, cu excepția cazului în care există un motiv întemeiat pentru a face acest lucru. Ceea ce face funcția noastră de hartă este o sarcină atât de comună, încât JavaScript are o metodă map() încorporată. Dacă utilizați această metodă, codul va arăta astfel:

Let bandoodle = band.map(odlify); let floodleship = fellowship.map(odlify); let bandizzle = band.map(izzlify); let fellowship = fellowship.map(izzlify);
Observați că nu există deloc indentație sau buclă. Desigur, atunci când procesăm date, undeva în profunzimea JavaScript, pot fi folosite bucle, dar aceasta nu mai este preocuparea noastră. Acum codul este atât concis, cât și expresiv. Mai mult, este mai simplu.

De ce este mai simplu acest cod? Poate părea o întrebare stupidă, dar gândește-te. Este mai simplu pentru că este mai scurt? Nu. Codul compact nu este un semn de simplitate. Este mai simplu, deoarece cu această abordare am împărțit problema în părți. Și anume, există două funcții care funcționează cu șiruri de caractere: oodlify și izzlify. Aceste funcții nu trebuie să știe nimic despre matrice sau bucle. Există o altă funcție - harta, care funcționează cu matrice. În același timp, este complet indiferent ce tip de date se află în matrice sau ce anume vrem să facem cu aceste date. Pur și simplu execută orice funcție care i-a fost transmisă, trecându-i elementele matricei. În loc să amestecăm totul, am separat procesarea șirurilor și procesarea matricei. De aceea codul final s-a dovedit a fi mai simplu.

Convoluția matricei

Deci, funcția de hartă este foarte utilă, dar nu acoperă toate opțiunile de procesare a matricei care folosesc bucle. Este bine în cazurile în care, pe baza unei anumite matrice, trebuie să creați una nouă cu aceeași lungime. Dar dacă avem nevoie, de exemplu, să adunăm toate elementele unui tablou numeric? Sau, ce se întâmplă dacă trebuie să găsiți cel mai scurt șir din listă? Uneori trebuie să procesați o matrice și, de fapt, să generați o singură valoare pe baza acesteia.

Să ne uităm la un exemplu. Să presupunem că avem o listă de obiecte, fiecare dintre acestea reprezentând un super-erou:

Const eroi = [ (nume: "Hulk", putere: 90000), (nume: "Spider-Man", putere: 25000), (nume: "Hawk Eye", putere: 136), (nume: "Thor", putere: 100000), (nume: „Văduva Neagră”, putere: 136), (nume: „Vision”, putere: 5000), (nume: „Vrăjitoare Stacojie”, putere: 60), (nume: „Mystique”, putere: 120), (nume: "Namora", putere: 75000), ];
Trebuie să găsim cel mai puternic erou. Pentru a face acest lucru, puteți folosi bucla for...of:

Fie cel mai puternic = (putere: 0); pentru (să fie erou al eroilor) ( dacă (erou.putere > cel mai puternic.puter) ( cel mai puternic = erou; ) )
Luând în considerare toate lucrurile, acest cod nu este chiar atât de rău. Facem o buclă prin matrice, stocând obiectul celui mai puternic erou la care ne-am uitat în variabila cea mai puternică. Pentru a vedea mai clar modelul de lucru cu o matrice, să ne imaginăm că trebuie să aflăm și puterea totală a tuturor eroilor.

Fie combinedStrength = 0; pentru (lăsați eroul eroilor) (combinatStrength += hero.strength; )
În fiecare dintre aceste două exemple există o variabilă de lucru care este inițializată înainte de a începe bucla. Apoi, în fiecare iterație, un element al matricei este procesat și variabila este actualizată. Pentru a evidenția și mai bine schema de lucru, vom muta operațiile efectuate în interiorul buclelor în funcții și vom redenumi variabilele pentru a sublinia asemănarea acțiunilor efectuate.

Funcția majoratStrength(campion, contender) ( return (contender.strength > champion.strength) ? contender: champion; ) function addStrength(tally, hero) ( return tally + hero.strength; ) const initialStrongest = (putere: 0); let working = initialStrongest; pentru (eroul eroilor) ( lucru = mai mareForță(lucrând, erou); ) const strongest = lucrător; const initialCombinedStrength = 0; lucru = initialCombinedStrength; for (eroul eroilor) ( lucru = addStrength(working, hero); ) const combinedStrength = work;
Dacă totul este rescris așa cum se arată mai sus, cele două bucle ajung să fie foarte asemănătoare. Singurul lucru care le distinge sunt funcțiile numite în ele și valorile inițiale ale variabilelor. În ambele bucle, matricea este restrânsă la o singură valoare. În terminologia engleză, o astfel de operație se numește „reducere”. Prin urmare, vom crea o funcție reduce care implementează modelul descoperit.

Funcția reduce(f, initialVal, a) ( lasă lucru = initialVal; for (lasă elementul a) (work = f(working, item); ) returnează lucrul; )
Trebuie remarcat faptul că, la fel ca și în cazul modelului de funcție de hartă, modelul de funcție de reducere este atât de răspândit încât JavaScript îl oferă ca o metodă de matrice încorporată. Prin urmare, dacă nu există un motiv special pentru aceasta, nu este nevoie să vă scrieți propria metodă. Folosind metoda standard codul va arata astfel:

Const strongestHero = eroi.reduce(greaterStrength, (force: 0)); const combinedStrength = heroes.reduce(addStrength, 0);
Dacă te uiți mai atent la rezultatul final, vei descoperi că codul rezultat nu este cu mult mai scurt decât a fost înainte, economiile sunt foarte mici. Dacă am fi folosit funcția reduce, scrisă noi înșine, atunci, în general, codul ar fi fost mai mare. Totuși, scopul nostru nu este să scriem cod scurt, ci să îi reducem complexitatea. Deci, am redus complexitatea programului? Pot spune că l-au redus. Am separat codul de buclă de codul care procesează elementele matricei. Ca urmare, secțiunile individuale ale programului au devenit mai independente. Codul s-a dovedit mai simplu.

La prima vedere, funcția reduce poate părea destul de primitivă. Cele mai multe exemple ale acestei funcții demonstrează lucruri simple, cum ar fi adăugarea tuturor elementelor matricelor numerice. Cu toate acestea, nicăieri nu spune că valoarea care reduce randamentele trebuie să fie de tip primitiv. Ar putea fi un obiect sau chiar o altă matrice. Când mi-am dat seama prima dată de asta, m-a uimit. Puteți, de exemplu, să scrieți o implementare a unei operații de mapare a matricei sau de filtrare folosind reduce . Vă sugerez să încercați singur.

Matrice de filtrare

Deci, există o funcție de hartă pentru a efectua operații pe fiecare element al matricei. Există o funcție de reducere care vă permite să comprimați o matrice la o singură valoare. Dar ce se întâmplă dacă trebuie doar să extragi unele dintre elementele din matrice? Pentru a explora această idee, să extindem lista de supereroi și să adăugăm câteva date suplimentare acolo:

Const eroi = [ (nume: "Hulk", putere: 90000, sex: "m"), (nume: "Spider-Man", putere: 25000, sex: "m"), (nume: "Hawk Eye", putere: 136, sex: "m"), (nume: "Thor", putere: 100000, sex: "m"), (nume: "Văduva Neagră", putere: 136, sex: "f"), (nume : „Viziune”, putere: 5000, sex: „m”), (nume: „Vrăjitoare Stacojie”, putere: 60, sex: „f”), (nume: „Mystique”, putere: 120, sex: „f”) "), (nume: "Namora", putere: 75000, sex: "f"), ]);
Acum să presupunem că există două probleme:

  1. Găsiți toți eroii de sex feminin.
  2. Găsiți toți eroii a căror putere depășește 500.
Este destul de posibil să abordăm soluția acestor probleme folosind vechiul for…of loop:

Fie femaleHeroes = ; for (let hero of heroes) ( if (hero.sex === „f”) ( femaleHeroes.push(hero); ) ) las supraoameni = ; pentru (lăsați eroul eroilor) ( dacă (eroul.puterea >= 500) ( superhumans.push(erou); ) )
În general, arată destul de decent. Dar aici un model care se repetă este vizibil cu ochiul liber. De fapt, buclele sunt exact aceleași, diferă doar în blocurile if. Ce se întâmplă dacă punem aceste blocuri în funcții?

Funcția esteFemaleHero(erou) ( return (erou.sex === "f"); ) funcția esteSuperom(erou) ( return (erou.putere >= 500); ) let femaleHeroes = ; for (lasă eroul eroilor) ( dacă (esteFemaleHero(erou)) ( femaleHeroes.push(hero); ) ) lasă supraoamenilor = ; pentru (lăsați eroul eroilor) ( dacă (este Superhuman(erou)) ( superoameni.împinge(erou); ) )
Funcțiile care returnează numai adevărat sau fals sunt uneori numite predicate. Folosim un predicat pentru a decide dacă stocăm următoarea valoare din matricea heroes într-o matrice nouă.

Modul în care am rescris codul l-a făcut mai lung. Dar, după evidențierea funcțiilor predicate, secțiunile repetate ale programului au devenit mai vizibile. Să creăm o funcție care ne va permite să scăpăm de aceste repetări:

Funcția filter(predicat, arr) (let working = ; for (let item of arr) ( if (predicate(element)) (work = working.concat(item); ) ) return working; ) const femaleHeroes = filter(isFemaleHero, eroii); const superhumans = filtru(esteSuperuman, eroi);
Aici, ca și în cazul funcțiilor de reducere și hărți încorporate, JavaScript are același lucru pe care l-am scris aici sub forma unei metode standard de filtrare pe obiectul Array. De aceea scrie functie proprie, cu excepția cazului în care este clar necesar, nu este necesar. Folosind mijloace standard codul va arata astfel:

Const femaleHeroes = heroes.filter(isFemaleHero); const superhumans = heroes.filter(isSuperhuman);
De ce este această abordare mult mai bună decât utilizarea unei bucle for...of? Gândiți-vă cum puteți utiliza acest lucru în practică. Avem o sarcină de genul: „Găsiți toți eroii care...”. Odată ce vă dați seama că puteți rezolva problema folosind funcția standard de filtru, treaba devine mai ușoară. Tot ce trebuie să facem este să spunem acestei funcții ce elemente ne interesează. Acest lucru se face prin scrierea unei funcții compacte. Nu este nevoie să vă faceți griji cu privire la procesarea matricelor sau a variabilelor suplimentare. În schimb, scriem o funcție de predicat minuscul și problema este rezolvată.

Și, ca și în cazul altor funcții care funcționează pe matrice, utilizarea filtrului vă permite să exprimați mai multe informații în mai puțin cod. Nu trebuie să citiți tot codul de buclă standard pentru a vă da seama ce anume filtrăm. În schimb, tot ce trebuie să înțelegeți este descris chiar atunci când metoda este apelată.

Căutați în matrice

Filtrarea este o operație foarte utilă. Dar ce se întâmplă dacă trebuie să găsești doar un super-erou din listă? Să presupunem că suntem interesați de Black Widow. Funcția de filtru poate fi folosită pentru a rezolva această problemă:

Funcția isBlackWidow(hero) ( return (hero.name === "Black Widow"); ) const blackWidow = heroes.filter(isBlackWidow);
Principala problemă aici este că o astfel de soluție nu este eficientă. Metoda de filtrare trece prin fiecare element al matricei. Cu toate acestea, se știe că în matrice un singur erou se numește Black Widow, ceea ce înseamnă că te poți opri după ce acest erou este găsit. În același timp, funcțiile predicate sunt convenabile de utilizat. Prin urmare, să scriem o funcție de căutare care va găsi și returna primul element potrivit:

Funcția find(predicate, arr) ( for (let item of arr) ( if (predicate(item)) ( return item; ) ) const blackWidow = find(isBlackWidow, heroes);
Aici, din nou, trebuie spus că JavaScript are o funcție încorporată care face exact ceea ce este necesar:

Const blackWidow = heroes.find(isBlackWidow);
Drept urmare, ca și înainte, am putut să ne exprimăm ideea mai concis. Folosind funcția de căutare încorporată, sarcina de a căuta un anumit element se reduce la o întrebare: „În ce criterii putem determina că elementul dorit a fost găsit?” Nu trebuie să vă faceți griji pentru detalii.

Despre funcțiile de reducere și filtrare

Cititorii au observat că este ineficient să parcurgeți lista de eroi de două ori în exemplele de mai sus pentru funcțiile de reducere și filtrare. Utilizarea operatorului de împrăștiere de la ES2015 vă permite să combinați convenabil două funcții de pliere a matricei într-una singură. Iată o bucată de cod modificată care vă permite să iterați prin matrice o singură dată:

Funcția processStrength((cel mai puternic Hero, combinedStrength), erou) ( return ( strongerHero: higherStrength(strongestHero, erou), combinedStrength: addStrength(combinedStrength, erou), ); ) const (strongest Hero, combinedStrength) = heroes (proces.Strength, erou) : (putere: 0), combinatStrength: 0));
Nu pot să nu observ că această versiune va fi puțin mai complicată decât cea în care matricea a fost parcursă de două ori, dar dacă matricea este uriașă, reducerea numărului de treceri peste ea poate fi foarte utilă. În orice caz, ordinea de complexitate a algoritmului rămâne O(n).

Rezultate

Cred că caracteristicile prezentate aici sunt un exemplu excelent de ce abstracțiile alese cu atenție sunt atât utile, cât și arată bine în cod. Să presupunem că folosim funcții încorporate ori de câte ori este posibil. În fiecare caz, rezultă următoarele:
  1. Scăpăm de bucle, ceea ce face codul mai concis și, cel mai probabil, mai ușor de citit.
  2. Șablonul utilizat este descris folosind un nume de metodă standard adecvat. Adică, mapați, reduceți, filtrați sau găsiți.
  3. Amploarea sarcinii este redusă. În loc să scrieți cod pentru a procesa singur matricea, trebuie doar să spuneți funcției standard ce să facă cu matricea.
Rețineți că în fiecare caz sunt utilizate funcții pure compacte pentru a rezolva problema.

De fapt, dacă te gândești la toate acestea, poți ajunge la o concluzie care, la început, pare surprinzătoare. Se pare că, dacă utilizați numai cele patru modele de procesare a matricei descrise mai sus, puteți elimina aproape toate buclele din codul dvs. JS. La urma urmei, ce se face în aproape fiecare buclă scrisă în JavaScript? Fie procesează, fie construiește o anumită matrice, fie le face pe ambele. În plus, JS are și alte funcții standard pentru lucrul cu matrice, le puteți învăța cu ușurință singur. A scăpa de bucle aproape întotdeauna reduce complexitatea programelor și scrie cod care este mai ușor de citit și întreținut.

Dragi dezvoltatori JavaScript, aveți ceva în minte? specificații standard, care vă permit să îmbunătățiți codul scăpând de unele construcții comune „de casă”?

Etichete: Adăugați etichete

Bucla for este cea mai folosită buclă în JavaScript.

Designul său arată astfel:

Pentru (început; condiție; pas) ( /* corpul buclei */ )

Este foarte simplu. Să ne uităm la un exemplu:

Var i; pentru (i = 1; i

În acest exemplu:

  • Începutul ciclului: i = 1 (pornind de la valoarea i = 1)
  • Starea ciclului: i
  • Etapa de ciclu: i++ (la fiecare pas al buclei i este crescut cu 1)
  • Corpul buclei: document.write("

    Numărul pasului ciclului este executat: " + "

    "); (afișează un mesaj pe ecran)

Algoritm pas cu pas pentru executarea acestei bucle for, mai detaliat:

  1. Începutul buclei: variabila i este setată la 1. Această parte a buclei este executată o dată.
  2. Se verifică condiția buclei (i 5) - sfârșitul buclei.
  3. Corpul buclei este executat.
  4. Pasul buclei este executat. În cazul nostru i++. Este întotdeauna executat după corpul buclei.
  5. Reveniți la punctul 2.

Dacă corpul buclei constă dintr-o instrucțiune, atunci bretele {...} nu este necesar să-l punem.

Variabila i nu dispare după terminarea buclei. Continuă să existe și valoarea sa după sfârșitul ciclului va fi egală cu 6.

Să rezumam aceste date într-un nou exemplu:

Var i; pentru (i = 1; i

Aici, bretele nu au fost folosite pentru a crea corpul buclei.

Bretele {...} formați un bloc în JavaScript - acesta este unul dintre constructele limbajului. Adică, dacă există acolade după instrucțiunea bucla for, aceasta înseamnă că handlerul JavaScript trebuie să execute întregul bloc JavaScript.

Similar unui bloc, puteți specifica o funcție într-o buclă for. Iată un exemplu:

Pentru (var i = 1; i

Dar atunci când declarați o funcție, există acolade {...} necesar. Absența lor va duce la o eroare.

Vă rugăm să rețineți că în această buclă variabila i este declarată la începutul buclei: for ( var i = 1; i

Sari peste piese

În general, începutul ciclului nu trebuie scris:

Var i = 1; pentru(;i

Vedeți, la începutul buclei există doar un punct și virgulă, iar bucla funcționează bine.

De asemenea, puteți elimina pasul:

Var i = 1; pentru(;i

Această buclă for s-a transformat într-un analog al buclei while (de exemplu

Puteți pune o expresie într-o condiție care modifică o variabilă.

Pentru (i = 10; i--;) ( document.write("

Se execută pasul buclei: " + i + ".

"); }

Deoarece interpretul JavaScript se așteaptă să primească o valoare booleană, orice valoare are ca rezultat un tip boolean, așa că atunci când următoarea scădere are ca rezultat variabila i 0 (fals), bucla se va opri.

Buclă infinită pentru

Da, da, știu că este corect să scrii infinit :)

Deci, bucla va fi nesfârșită dacă condiția este întotdeauna adevărată. Iată un exemplu:

Pentru (var i = 1; i

În acest exemplu, variabila i va scădea și nu va deveni niciodată mai mare de cinci. Bucla va rula pentru totdeauna. Încercați să rulați acest script. Pentru mine, Chrome „s-a pierdut în gânduri” și nu a afișat nimic pe ecran, dar a continuat să gândească și să gândească.

Aveți grijă să evitați crearea accidentală de bucle nesfârșite.

Întreruperea buclei for

Pentru a întrerupe o buclă for, la fel ca pentru a întrerupe orice altă buclă, utilizați comanda break. Când motorul JavaScript întâlnește o comandă de pauză în corpul unei bucle, oprește executarea buclei și începe să execute instrucțiunile de script care urmează buclei. Dacă există.

În exemplul următor, vom opri bucla la a treia iterație (al treilea pas).

Pentru (var i = 1; i

Să complicăm puțin exemplul

Să efectuăm doar 100 de iterații ale buclei infinite.

Var $contor = 1; pentru (var i = 1; i

Următoarea iterație: continua

Comanda continue încheie iterația curentă și începe următoarea.

Directiva continue este „sora mai mică” a directivei break, oprește doar iterația, și nu întreaga buclă.

Pentru (var i = 1; i

Bucla de mai jos folosește continuare pentru a scoate valori impare:

Pentru (var i = 0; i

Desigur, valorile impare pot fi scoase folosind o buclă ca aceasta fără o directivă continue:

Pentru (var i = 0; i

Directivele break/continuare în „?"

Să descriem pe scurt operatorul semnul întrebării"?". Este similar cu un construct if.

Design logic:

Dacă (condiție) ( a(); ) else ( b(); )

Funcționează la fel ca și codul cu operatorul „?”.

Condiție? a() : b();

var i = 2; document.write("

Partea 1.

"); dacă (i == 2) document.write("

Condiția a funcționat.

"); else document.write("

Condiția nu a funcționat.

"); document.write("

Partea 2.

"); dacă (i == 2) document.write("

"); i == 2 ? document.write("

"); else document.write("

");

"): document.write(" Asa de, important

, nu puteți folosi pauză/continuare în dreapta operatorului „?”

În JavaScript, constructele sintactice care nu returnează valori sunt interzise să fie folosite în operatorul „?”.

Pentru (var i = 0; i

Exemplul de mai jos nu funcționează, conține o eroare:

Etichete pentru pauză/continuare

Uneori devine necesar să se creeze bucle imbricate. Într-un astfel de caz, în timp ce bucla imbricată rulează, poate fi necesar să opriți bucla părinte sau să opriți iterația buclei părinte. Etichetele sunt folosite pentru aceasta.

Puteți folosi etichete pentru a desemna bucle, apoi utilizați break sau continuați pentru a ieși din buclă sau continuați bucla cu o nouă iterație.

Markerii sunt singura modalitate prin care comenzile de pauză și continuare pot afecta execuția buclei exterioare.

Instrucțiunea de etichetă este utilizată numai împreună cu break sau continuă să ofere o ieșire alternativă dintr-o buclă.

Eticheta are sintaxa „nume:”, numele etichetei trebuie să fie unic. Marcajul este plasat înaintea ciclului, în aceeași linie sau cu o întrerupere de linie.

În mod similar, puteți utiliza directiva break în acest loc. Dar dacă îl folosiți, după cum înțelegeți, execuția ciclurilor se va opri.

Var i, j; metka1: pentru (i = 0; i

JavaScript nu are o instrucțiune goto precum PHP, este posibil să se utilizeze doar etichete break sau continue.