Standardne petlje
Često se javlja potreba da se unutar programa neke linije koda izvršavaju više puta. Ovaj način izvršavanja se ostvaraju pomoću odgovarajućih upravljačkih struktura. Petlje i iteracije su osnovni gradivni element svakog programa. Standardne petlje se javljaju manje više u istom obliku u skoro svim programskim jezicima. Najkorišćenija je “for petlja”. Posebnu pažnju treba obratiti na while petlje jer postoji mogućnost da petlja usled lošeg izbora uslova postane beskonačna.
“while” petlja
While izraz se izvršava sve dok je uslov TRUE, a ukoliko nije onda se izlazi iz petlje. Ovaj tip petlje se najčešće koristi kada se ne zna tačan broj izvšenja petlje. U slučaju da uslov na samom početku nije ispunjen, petlja se ne izvršava ni jednom. Pre ulaska u petlju vrši se inicijalizacija promenljivih koje će biti korišćene bilo u uslovu, bilo u telu petlje. U telu petlje se nalazu kod koji formira uslov za ostanak u petlji.
1 2 3 |
while ([uslov]) { izraz za izvršenje ako je uslov TRUE } |
Ovaj tip je nazvan “pre-test loop” jer se uslov izvršava pre bloka sa izrazom.
1 2 3 4 5 6 7 |
var n = 0; var x = 0; while (n < 3) { n++; x += n; } alert ("Ukupan zbir niza je " + x) |
Izraz “n++” se naziva “updater”. Najčešće se pre petlje definišu početne vrednosti za uslov. Obratiti pažnju na mogućnost stvaranja “beskonačne petlje” ukoliko nema updater-a.
1 2 3 |
while (true) { console.log('Hello, world!'); } |
do..while petlja
Izraz u okviru do…while petlje se izvršava sve dok uslov ne bude FALSE. Razlika izmedju “do…while” i “while” petlje je ta da se ovde izraz bar jednom izvrši, dok kod “while” postoji mogućnost da se izraz nikad ne izvrši ako je uslov u startu FALSE.
1 2 3 |
do { izraz za izvršenje } while ([uslov]); |
Ovaj tip petlje se najčešće koristi kada izraz u telu petlje generiše vrednost koja će se koristiti u uslovu.
1 2 3 4 5 |
var i = 0; do { i += 1; console.log(i); } while (i < 5); |
“for” petlja
Ovo je najčešće korišćena petlja. Za razliku od “while” i “do…while” petlji gde su ključne tačke petlje [početna vrednost], [uslov] i [izraz za povećavanje] na različitim mestima, ovde ih struktura zvana “iteration statement” drži na okupu, u jednom redu, odvojene sa tačaka-zarezom.
1 2 3 |
for ([početna vrednost]; [uslov]; [izraz za povećenje]){ izraz za izvršenje } |
Ovaj tip petlje se koristi ukoliko se na početku zna tačan broj izvršenja petlji.
1 2 3 4 5 |
var sum = 0; for (var i = 1; i <= 50; i++) { sum = sum + i; } alert("Sum = " + sum); |
Dodatne naredbe
break
Izraz break se koristi da se iskoči iz tela petlje. Nalazi se negde u telu petlje, obično iza nekog dodatnog uslova. Može se koristiti uz bilo koji pomenuti tip petlje.
BREAK u FOR petlji
1 2 3 4 5 6 7 |
var text = ""; var i; for (i = 0; i < 10; i++) { if (i === 3) { break; } text += "Broj manji od 3 je " + i + "\n"; } console.log(text); |
Rezultat je:
1 2 3 |
Broj manji od 3 je 0 Broj manji od 3 je 1 Broj manji od 3 je 2 |
continue
Sa naredbom continue se ne prekida izvršenje iteracija, već se preskače trenutna iteracija.
continue u FOR petlji
1 2 3 4 5 6 7 |
var text = ""; for (var i = 0; i < 5; i++) { //Ako je broj jednak 3 onda ga ne štampaj if (i === 3) { continue; } text += "broj " + i + '\n'; } console.log(text); |
Rezultat je:
1 2 3 4 5 |
broj 0 broj 1 broj 2 broj 4 broj 5 |
continue u WHILE petlji
1 2 3 4 5 6 7 8 9 |
var x = 0; var text = ""; while (x < 5) { x = x + 1; //Ako je broj jednak 3 onda ga ne štampaj if (x == 3){ continue; } text += "broj " + x + '\n'; } console.log( text ) |
Rezultat:
1 2 3 4 |
broj 1 broj 2 broj 4 broj 5 |
Loop labels
Loop labels je sintaksa koja omogućava obeležavanje petlji. Label (naziv petlje) se stavlja ispred svake petlje zajedno sa dvotačkom.
1 2 3 4 5 6 7 |
spoljnaPetlja: for( ) { // ... unutrasnjaPetlja: for( ) { // ... } } |
Obeležavanje petlji nam daje mogućnost da pri korišćenju break ili continue naredbi, možemo da izaberemo petlju na koju želimo da primenimo naredbe.
1 2 3 4 5 6 7 8 9 10 |
petlja_1: for (var i in set1) { petlja_2: for (var j in set2) { petlja_3: for (var k in set3) { break petlja_2; // izlazak iz petlji: petlja_3 i petlja_2 } } } |
Iteracija kroz nizove forEach()
Ova metoda izvršava odredjenu funkciju (callback) koristeći svaki elemenat prosledjenog niza. Ova funkcija je manje fleksbilna od standardne “for petlje” jer nema uslovne izraze i ne postoji mogućnost da se prekine jednom započeti “loop” osim da izbaci izuzetak. Callback funkciji metoda prosledjuje tri parametra:
- vrednost člana niza
- indeks člana niza
- niz (nad kojim se izvršava metoda)
1 2 3 |
nekiNiz.forEach(function (currentValue, index, array) { //neki proracun }, [thisArg]); |
Pored callback funkcije može (opciono) da se prosledi i argument thisArg, koji definiše na šta će da ukazuje rezervisana reč this u okviru callback funkcije. Sama funkcija ne vraća ništa automatski, stoga nije “chainable” (na nju se ne može na ulančati sledeća metoda). Čak i posle eksplicitnog korišćenja return izraza, neće vratiti ništa posle iteracije.
Primer
1 2 3 4 5 |
var nekiNiz = ['a', 'b', 'c']; nekiNiz.forEach(function(element) { console.log(element); }); //Vraca: "a" "b" "c" |
Isti rezultat može da se dobije koristeći druge atribute
1 2 3 4 5 |
var nekiNiz = ['a', 'b', 'c']; nekiNiz.forEach(function(element, index, prosledjen_niz) { console.log(prosledjen_niz[index]); }); //Vraca: "a" "b" "c" |
Primer
Callback funkcija ne može da koristi u proračunu “prazne članove niza” (član niza sa indeksom kome nije prodružena vrednost). Stoga u narednom primeru ova metoda neće uzimati u obzir prazan element, pa će član niza sa indeksom 2 biti preskočen:
1 2 3 4 5 |
function callbackFunkcija(element, index, array) { console.log('a[' + index + '] = ' + element); } [2, 5, , 9].forEach(callbackFunkcija); // Vraća: a[0] = 2 a[1] = 5 a[3] = 9 |
Iteracija kroz objekat for..in
Ovo je specifična “for” petlja koja prolazi kroz sva svojstva nekog objekta kod kojih je deskriptor svojstva enumerable, setovan na TRUE. Ovaj način može da se primeni i na nizove ali ima ograničenja i puno neželjenih sporednih efekata, pa je preporuka da se iteraciju kroz nizove ipak koristi neki drugi način (npr. “for…of” petlja).
NAPOMENA:
Treba naglasiti da kod ovog načina iteracije nije zagarantovan redosled članova iteracije.
1 2 3 4 5 6 7 |
var person = {fname:"John", lname:"Doe", age:25}; var text = ""; var key; for (key in person) { text += person[key] + " " + "\n"; } console.log( text ); |
Rezultat je:
1 2 3 |
John Doe 25 |
NAPOMENA:
for…in petlja “prolazi” čak i svojstva koja se nasledjuju kroz prototype objekat roditelja.
1 2 3 4 5 6 7 8 9 10 11 12 |
var Programer = function(ime, specijalnost) { this.ime = ime; this.specijalnost = specijalnost; } Programer.prototype.profesija = "programer"; var dragoljub = new Programer("Dragoljub", "javascript"); var text = ""; for (var item in dragoljub) { text += dragoljub[item] + " " + "\n"; } console.log (text); |
Ova petlja će vratiti svojstva objekta dragoljub (Dragoljub, javascript) ali i nasledjeno svojstvo od roditelja (programer). Ukoliko želimo ipak da vratimo samo “lična” svojstva objekta, moramo da filtriramo koristeći metodu hasOwnProperty, kao u sledećem primeru:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var Programer = function(name, specijalnost) { this.name = name; this.specijalnost = specijalnost; } Programer.prototype.profesija = "programer"; var dragoljub = new Programer("Dragoljub", "javascript"); var text = ""; for (var item in dragoljub) { if (dragoljub.hasOwnProperty(item)) { text += dragoljub[item] + " " + "\n"; } } console.log (text); |
Ovaj kod vraća samo lična svojstva objekta “dragoljub“: Dragoljub i javascript.
NAPOMENA:
“for..in” petlja prolazi kroz sva svojstva objekta, pa čak i kroz ona koja nasledjuje kroz lanac nasledjivanja, stoga ako nas interesuj samo “lična” svojstva objekta postoji mogućnost transformacije objekta u niz. Za to se koristi jedno od sledećih metoda: Object.values(obj), Object.keys(obj) ili Object.entries(obj). Više o ovim metodama pročitajte u članku “Object() & Object.prototype”
Iteracija kroz iterable for..of
Ovo je novi način iteracije koji je došao u paketu sa ES6 standardom. Iteracija sa “for…of” prolazi kroz vrednosti iterabilne kolekcije. Koristi se za sve iteratibilne kolekcije (Array, Map, Set, String…), ali nije planiran za iteraciju kroz svojstva objekata.
1 2 3 |
for (promenjiva of kolekcija) { izraz za izvršenje } |
gde je:
- vrednostClana – predstavlja novu vrednost koja se dodeljuje pri svakoj iteraciji
- kolekcija – naziv kolekcije kroz čija svojstva se vrše iteracije
Za razliku od for…in gde nije garantovan stalni redosled iteracije, kod ovog načina se iteracije vrše prema redosledu.
1 2 3 4 5 6 7 |
let nekiNiz = []; nekiNiz[3] = 'd'; nekiNiz[0] = 'a'; nekiNiz.foo = 'f'; for (let vrednostClana of nekiNiz) { console.log(vrednostClana); } |
Rezultat:
1 2 3 4 |
"a" // a[0] undefined // a[1] undefined // a[2] "d" // a[3] |
Iteracija kroz “niz”
1 2 3 4 5 6 7 8 9 |
let nizBrojeva = [10, 20, 30]; for (let clanNiza of nizBrojeva) { var duplo = clanNiza *2 ; console.log(duplo); } // 20 // 40 // 60 |
Iteracije kroz “string”
1 2 3 4 |
const str = 'dragoljub'; for ( const chr of str ){ console.log(chr); // 'd', 'r', 'a', 'g', 'o', 'lj', 'u', 'b' } |
Iteracije kroz DOM
1 2 3 4 5 |
const articleParagraphs = document.querySelectorAll("article > p"); for ( const paragraph of articleParagraphs ) { paragraph.classList.add("read"); } |
Iteracije kroz MAP
1 2 3 4 5 |
const m = new Map([['foo', 'hello'], ['bar', 'world']]); for ( const [name, value] of m ) { console.log(name + "->" + value); //"foo->hello", "bar->world" } |
Iteracija kroz Set
1 2 3 4 5 |
const s = new Set(['foo', true, 42]); for ( const value of s ) { console.log(value); // 'foo', true, 42 } |
Iteracija kroz generatore
1 2 3 4 5 6 7 8 9 10 |
function *foo() { yield 'foo'; yield false; yield 42; yield 'bar'; } for (const v of foo() ) { console.log( v ); // 'foo', false, 42, 'bar' } |
Iteracija kroz objekat
Iako ovaj način iteracije nije planiran za iteraciju objekta, ipak postoji zabilazni način da se primeni i na objektima koristeći Object.keys():
1 2 3 4 5 |
const obj = { foo : 'hello', bar : 'world' }; for ( const key of Object.keys(obj) ) { console.log(key + "->" + obj[key]); // 'foo->hello', 'bar->world' } |