nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 25.12.2020.

trejler_olovka Poslednja izmena: 16.04.2021.

trejler_dokument Jezici: JavaScript

trejler_teg_narandzasti Težina: 6/10

JavaScript
dom
es6
nizovi
mapiranje
arrow funkcije
lambda funkcije
web dizajn
frontend
fullstack
internet
teorija
saveti

Tema: JavaScript

Uvod u JavaScript i DOM (Document Object Model)JavaScript ES6 sintaksaUvod u Node.jsAsinhrono programiranje u JavaScriptu

Povezani članci

Tutorijal - Implementacija struktura podataka u programskom jeziku JavaScriptJSON - tekstualni format za razmenu podatakaUvod u PHP i back-end programiranjeUvod u PythonRegularni izrazi - napredna pretraga tekstaStrukture podatakaKlase složenosti algoritama (O notacija)Operacije sa bitovima u programskom jeziku CIzbor prvog programskog jezikaASCII, Unicode i UTF - Predstavljanje znakova na računarima
Svi članci
The only way to learn a new programming language is by writing programs in it.
Dennis Ritchie

Operacije sa nizovima u programskom jeziku JavaScript

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Teorija

Uvod

Nizovi u JavaScript-u deklarišu se i inicijalizuju na vrlo komotan način, ne podležu strogoj tipizaciji (niz može sadržati elemente različitog tipa), interna implementacija nizova je relativno kompleksna, a ako bismo baš hteli, našli bismo bar još koju 'zamerku'. :)

Međutim, mora se priznati da ima 'šarma i lepote' u radu sa nizovima u JS-u (ima i svega navedenog iz prethodnog pasusa; nismo zaboravili), i mora se priznati da, u većini uobičajenih situacija (naravno - pod uslovom da "pazimo šta radimo"), stvari zapravo funkcionišu prilično glatko.

Pristup koji predlažemo čitaocima (i koji primenjujemo u praksi), podrazumeva sledeće: kad već programski jezik dozvoljava "sve i svašta", uputno je da preuzmemo na sebe vođenje računa o bitnim stvarima, i postupamo sa nizovima onako kako bismo postupali da koristimo jezik sa strogom tipizacijom, a onda (ukoliko postupamo (dovoljno) pažljivo), JavaScript neće priređivati neprijatna iznenađenja ....

Osnovne operacije sa nizovima

Za početak (pre nego što se posvetimo osnovnim operacijama za rad sa nizovima), ukratko ćemo razmotriti šta se (uopšte) u JavaScript-u podrazumeva pod pojmom "niz", jer krajnji rezultat zavisi od endžina koji se koristi * i stoga ne možemo biti sigurni šta se dešava "ispod haube" gde "niz" može biti zapisan: bilo kao statički niz, bilo kao hash-mapa, sve u zavisnosti od okolnosti (i tako da programeri i krajnji korisnici nemaju uticaja na izbor formata).

Ovoga puta bićemo praktični i nećemo ulaziti u detaljniju diskusiju o implementaciji nizova (ostavićemo to za neku drugu priliku), ali, za sada ćemo niz u JavaScript-u definisati kao poseban tip promenljive koja omogućava smeštanje kolekcija podataka preko jednog identifikatora (naziva promenljive), ** pri čemu podaci ne moraju biti istog tipa, i pri čemu je moguće proizvoljno dodavati ili uklanjati elemente.

* JavaScript endžin je program koji se koristi za interpretaciju JS koda unutar drugog programa (tipično, unutar browsera).

Najpoznatiji JS endžini su V8 (koji se koristi u programu Google Chrome i okruženju Node.js), i SeaMonkey (koji se koristi u programu Mozilla Firefox).

** Naravno, pojedinačnim elementima se pristupa preko odgovarajućih indeksa (više o svemu u nastavku).

Deklaracija niza

Osnovni vid deklaracije niza u JS-u, praktično podrazumeva i inicijalizaciju praznog niza u istoj liniji koda (jer, ukoliko izostane inicijalizacija, promenljiva neće biti referenca na (prazan) niz, već, objekat sa sistemskom vrednošću null):

		
let niz = [ ];
		
	
Slika 1. - Deklaracija niza u JavaScript-u.

Niz je prazan, ali, svakako se u daljem toku izvršavanja programa mogu dodavati novi elementi.

Uskoro ćemo pokazati kako se u nizove dodaju novi elementi.

Inicijalizacija niza

Pored inicijalizacije praznog niza (što smo videli u prethodnom odeljku), često * se javlja i inicijalizacija/deklaracija koja podrazumeva zadavanje (nekoliko) elemenata:

		
let niz   = [ 1, 2, 2, 3, 4, 5, 5 ];
let imena = [ "Milan", "Petar", "Jovan" ];
		
	
Slika 2. - Inicijalizacija niza.

* Na slici #2 je prikazan najuobičajeniji način generisanja nizova u JS-u (promenljiva se deklariše kao niz, koji se odmah popunjava elementima).

Nizovi se takođe mogu inicijalizovati i preko funkcija (čija je povratna vrednost referenca na početak niza).

		
// Primer #1:
let niz = funkcijaKojaVracaNiz(ulaz);

// Primer #2:
let s     = "papir;kamen;makaze";
let lista = s.split(";"); // [ "papir" , "kamen" , "makaze" ]
		
	
Slika 3. - Inicijalizacija niza - preko funkcije koja vraća referencu na prvi element niza.

Što se tiče inicijalizacija koje smo videli na slici #3, na scenu stupa "preuzimanje odgovornosti sa naše strane".

Ako se za inicijalizaciju koristi funkcija koju smo definisali sami, ne treba prihvatati "zdravo za gotovo" da će funkcija svaki put vratiti uredno inicijalizovan niz, to jest, treba se postarati da funkcija - ukoliko dođe do greške - ponudi adekvatnu informaciji o pojavi greške, na jedan od sledeća dva načina:

  • preko povratne vrednosti po kojoj se može prepoznati da je došlo do greške (na primer, povratna vrednost može biti prazan niz - u situaciji u kojoj je očekivani rezultat bio niz sa izvesnim brojem elemenata)
  • preko odgovarajućeg izuzetka (u kom slučaju je potrebno koristiti blok try-catch)

Ukoliko umesto DIY funkcija koristimo gotova rešenja, potrebno je konsultovati dokumentaciju i (naravno) - potrebno je biti pažljiv.

.... a funkciju split ćemo detaljnije predstaviti kasnije u članku.

Pristup elementima

Pristup elementima niza obavlja se na način koji je uobičajen u programskom jeziku C: u velikoj zagradi, navodi se indeks (tj. 'redni broj traženog elementa').

		
let imenaNiz = [ "Dejan" , "Milan" , "Jovan" ];
let imeOsobe = imenaNiz[2]; // "Jovan"
		
	
Slika 4. - Pristup elementu niza.

Indeksiranje elemenata takođe je rešeno po uzoru na C, što praktično znači da prvi element ima indeks 0 (tj. nema indeks 1). **

* Navedeni način pristupanja elementima može se smatrati donekle "čudnim", budući da "niz" u JavaScript-u ("najverovatnije" ?!) nije implementiran kao statički niz, ali, bićemo praktični: iako znamo da (najverovatnije) nisu u pitanju statički nizovi - nećemo se previše brinuti oko svih navedenih pojedinosti.

** Budući da je indeks prvog elementa 0, jasno je da se u nizu od (npr) 5 elemenata, ne može pristupiti elementu a[5], već je poslednji element kome se može pristupiti a[4].

Očitavanje dužine niza (length)

Dužina niza (tj. broj elemenata), očitava se preko svojstva length:

		
let d = niz.length;
		
	
Slika 5. - Određivanje dužine niza.

Sada možemo (recimo) napraviti i for petlju koja pristupa svim elementima:

		
for (let i = 0; i < d; ++i) {
	niz[i] = niz[i] + 1;
}
		
	
Slika 6. - For petlja u kojoj se koristi prethodno ustanovljena dužina niza.

Kao i mnogi drugi jezici, JavaScript raspolaže i "specijalizovanom for petljom" koja je specifično namenjena prolasku kroz ceo niz (u pitanju je konstrukcija forEach, kojoj ćemo više pažnje posvetiti pred kraj).

Dodavanje elementa na kraj niza (push)

Za dodavanje elementa na kraj niza, koristi se funkcija push:

		
// [ 1, 2, 2, 3, 4, 5, 5 ]
niz.push(10); // [ 1, 2, 2, 3, 4, 5, 5, 10 ]
		
	
Slika 7. - Funkcija push - dodavanje elementa na kraj niza.

Za dodavanje elementa (ili elemenata) na proizvoljnu poziciju, koristi se funkcija splice (više o funkciji splice, u nastavku, posle opisa funkcija pop i shift).

Uklanjanje elemenata sa početka ili kraja niza (pop i shift)

Kada je u pitanju uklanjanje elemenata, razlikuju se tri slučaja:

  • uklanjanje elementa sa kraja niza
  • uklanjanje elementa sa početka niza
  • uklanjanje elementa sa proizvoljne pozicije

Element sa kraja niza, uklanja se preko funkcije pop:

		
// niz: [ 1, 2, 2, 3, 4, 5, 5, 10 ]
let p = niz.pop();

// p:   10
// niz: [ 1, 2, 2, 3, 4, 5, 5 ]
		
	
Slika 8. - Funkcija pop - Uklanjanje elementa sa kraja niza.

Element sa početka niza, uklanja se preko funkcije shift:

		
// niz: [ 1, 2, 2, 3, 4, 5, 5 ]
let p = niz.shift();

// p:   1
// niz: [ 2, 2, 3, 4, 5, 5 ]
		
	
Slika 9. - Funkcija shift - Uklanjanje elementa sa početka niza.

U idejnom smislu, može se reći da funkcija shift nalikuje bitovskom operatoru <<.

Za uklanjanje elementa sa proizvoljne pozicije, koristi se (već pomenuta) funkcija splice, s tim da je u pitanju univerzalna funkcija preko koje je moguće obaviti: i dodavanje, i uklanjanje.

Funkcija splice - dodavanje i/ili uklanjanje elemenata na proizvoljnoj poziciji

Poslednje što smo naveli u prethodnom odeljku može delovati pomalo čudno, ali, funkcija splice je veoma univerzalna i može se koristiti za obe operacije:

		
niz.splice(indeks, n_uklanjanje, elementi_za_dodavanje ....);

// indeks       - indeks na kome se obavlja dodavanje, ili
//                od koga počinje uklanjanje
// n_uklanjanje - broj elemenata koje treba ukloniti
// elementi     - lista elemenata koji će biti dodati
		
	
Slika 10. - Funkcija splice - Univerzalna funkcija za uklanjanje i dodavanje elemenata.

Kao što vidimo, zaista veoma univerzalno, s tim što preostaje pitanje kako to (sve) funkcioniše u praksi?!

Usput: sam naziv funkcije - eng. "splice" (koji možda deluje pomalo neobično), u prevodu označava "uplitanje" (konopaca, žica i sl).

Dodavanje elemenata

Za dodavanje elemenata, potrebno je postaviti indeks na poziciju koja odgovara mestu na kome treba da se pojavi prvi element iz liste novih elemenata, i (takođe), potrebno je naglasiti da se nijedan element ne uklanja (drugi argument je 0).

Od trećeg argumenta počinje lista elemenata koji se umeću.

Ako je i indeks za umetanje, a n broj elemenata za umetanje, cela operacija podrazumeva umetanje liste od n elemenata između pozicija i i i + 1.

		
let niz = [ 1 , 2 , 3 , 4 , 5 ]

niz.splice(2, 0, 1001, 1002)
// [ 1 , 2 , 1001 , 1002 , 3 , 4 , 5 ] 
		
	
Slika 11. - Primer dodavanja elemenata preko funkcije splice.

U konkretnom primeru: između druge i treće pozicije, umeću se dva nova elementa (1001 i 1002).

Uklanjanje elemenata

Za uklanjanje elemenata, potrebno je navesti dva argumenta koji (redom) predstavljaju indeks prvog elementa koji se uklanja i ukupan broj elemenata koje je potrebno ukloniti.

		
let niz = [ 1 , 2 , 3 , 4 , 5 ]

niz.splice(2, 1)
// [ 1 , 2 , 4 , 5 ] 
		
	
Slika 12. - Primer uklanjanja elemenata preko funkcije splice.

U konkretnom primeru: na trećoj poziciji (indeks 2), uklonjen je jedan element.

Ako se funkciji predaju (samo) dva argumenta, jasno je da nema dodavanja.

Kombinovani pristup

Po potrebi, prethodne dve operacije moguće je kombinovati (pri čemu se obavezno predaje tri ili više argumenata).

Prvo se uklanja određeni broj elemenata, počevši od indeksa koji je naveden kao prvi argument (uklanja se onoliko elemenata koliko je navedeno preko drugog argumenta), a zatim se umeću novi elementi, * na mesto koje (praktično) odgovara poziciji na kojoj je došlo do uklanjanja.

		
let niz = [ 1 , 2 , 3 , 4 , 5 ]

niz.splice(2, 2, 2001, 2002)
// [ 1 , 2 , 2001, 2002, 5 ] 
		
	
Slika 13. - Primer kombinovanog uklanjanja i dodavanja preko funkcije splice.

* I ovoga puta treći argument predstavlja prvi element iz liste elemenata koji će biti umetnuti.

U konkretnom primeru: prvo se uklanjaju elementi sa indeksima 2 i 3 (dva elementa, počevši od indeksa 2), a zatim se između novih indeksa 1 i 2 (ili, uslovno rečeno, između prvobitnih indeksa 1 i 4), umeću novi elementi (2001 i 2002).

Spajanje nizova (concat)

U JavaScript-u (pogotovo u jednostavnijim situacijama), dva niza se tipično spajaju preko funkcije concat, na sledeći način:

		
let a = [ 1, 2, 3 ];
let b = [ 4, 5, 6 ];
let c = a.concat(b); // [ 1, 2, 3, 4, 5, 6 ]
		
	
Slika 14. - Funkcija concat - Spajanje nizova.

Naziv funkcije, "concat", skraćenica je engleskih reči "concatenate" ili "concatenation" (izraz se prevodi kao 'konkatenacija', * a označava nadovezivanje niski znakova, ili, u određenim programskim jezicima, nizova opšteg tipa).

* Izraz 'konkatencija' se retko koristi u praksi (čak i u diskusijama akademskog tipa).

Spajanje niza u nisku znakova (join)

Za spajanje niza elemenata u nisku, tipično * se koristiti funkcija join:

  • ukoliko se funkciji join ne preda argument, rezultujuća niska nastaje direktnim spajanjem elemenata niza, uz dodavanje zareza između svaka dva susedna elementa
  • ukoliko se funkciji join kao argument preda niska (koja predstavlja crtu, prelazak u novi red i sl), predata niska pojavljuje se u okviru rezultujuće niske, između svaka dva elementa prvobitnog niza (videti donji primer)
		
let a  = [ "N", "i", "z", "o", "v", "i" ];
let s1 = a.join();    // "N,i,z,o,v,i"
let s2 = a.join("*"); // "N*i*z*o*v*i"
let s2 = a.join("");  // "Nizovi"
		
	
Slika 15. - Funkcija join - Spajanje elemenata niza u nisku znakova.

U obradi tekstualnih datoteka, funkcija join koristi se često (baš kao i funkcija split koju ćemo prikazati u narednom odeljku).

* Kada kažemo da se operacije spajanja nizova i spajanja nizova u nisku "tipično" obavljaju preko funkcija concat i join, na posredan način nagoveštavamo da postoji mogućnost da se ove dve operacije obave drugačije, preko funkcija koje programeri mogu implementirati samostalno, ali, "tipično"/"uobičajeno", navedene operacije spajanje nizova obavljaju se preko funkcija koje smo opisali (a sličan način razmišljanja važi i za druge operacije koje smo navodili i koje ćemo tek navoditi).

Takođe, iako (i ovoga puta) preporučujemo da budete pažljivi pri korišćenju JS funkcija, to jest, preporučujemo da funkciju join koristite samo za spajanje nizova niski, napomenimo da je funkcija join u stanju da spaja nizove brojčanih vrednosti, kao i mešovite nizove (ali, još jednom, preporučujemo da takve kodove izbegavate).

Pretvaranje niske znakova u niz (split)

Deljenje niske obavlja se preko funkcije split, pri čemu se kao kriterijum za podelu koristi određena niska ili regularni izraz.

Pod uslovom da ulazna niska sadrži nisku koja se predaje kao argument (u donjem primeru: "-"), rezultat je lista 'okolnih podniski':

		
let s = "Pariz-London-Lisabon";
let a = s.split("-"); // [ "Pariz", "London", "Lisabon" ]
		
	
Slika 16. - Funkcija split - Kreiranje niza podelom niske znakova.

Kao što smo pomenuli, funkcije join i split veoma dobro dođu u obradi teksta, a da bismo što bolje ilustrovali upotrebnu vrednost navedenih funkcija, napisaćemo jednostavnu skriptu čiji je zadatak da pravilno formatira listu imena u kojoj se separatori (tj. znakovi za razdvajanje), ne koriste na dosledan način:

		
// Dobre informacije, ali, nedosledna
// upotreba znakova za razdvajanje:
let s = "Milan Ivan, Jovan # Dejan";

// Donji regularni izraz praktično predstavlja
// kolekciju svih "razdvajača":
let regex = /([ ,#])/

let lista = s.split(regex); // [ "Milan", " " , "Ivan", ",",
                            //   " ", "Jovan", " ", "#",
                            //   " " , "Dejan" ]

// Napomena: u praksi, lista bi sadržala i
// nekoliko praznih stringova ("")

let nova_lista = [];

for (let i = 0; i < lista.length; ++i) {
	// Ako je element liste prazna niska ili neki
	// od separatora, nećemo takav element ubacivati
	// u novu listu:
	if (lista[i] == "" || lista[i].match(regex)) {
		continue;
	}
	
	// Svi ostali elementi (praktično - samo imena),
	// ubacuju se u novu listu:
	nova_lista.push(lista[i]);
}

// Na kraju, lista se spaja u ("običnu") nisku,
// u kojoj će svako ime biti zapisano u novom redu

let s2 = nova_lista.join("\n");
		
	
Slika 17. - Praktičan primer korišćenja funkcija split i join.

Skripta kreira listu (preko funkcije split), prolazi kroz sve elemente liste, izdvaja imena i, na kraju, od liste formira ("običnu") nisku, preko funkcije join.

Funkcije višeg reda za obavljanje operacija sa nizovima

Funkcije koje smo do sada prikazali u članku nisu (ni iz daleka) "sve" funkcije koje se u JS-u koriste za obavljanje operacija sa nizovima, već samo one koje smatramo najkorisnijim za sam početak (kao i većinu 'svakodnevnih' zadataka), međutim, iako smo članak namenili pre svega čitaocima sa 'ne-baš-mnogo' iskustva, osvrnućemo se i na nekolicinu (ponešto) naprednijih funkcija za rad sa nizovima, koje se obično koriste u sprezi sa tzv. "lambda notacijom".

U svakom slučaju, ne dajte da vas termini kao što su "funkcije višeg reda" i "lambda izrazi" uplaše i odvrate, jer ipak su u pitanju relativno jednostavne tehnike sa kojima se većina programera (čak i mlađih i/ili neiskusnijih), može na početku upoznati na jednostavan i intuitivan način (bez opterećenja i sl).

Za sam početak, neka bude tako kako smo naveli, ali, uskoro (kada dođe vreme), biće potrebno da se detaljnije upoznate sa sintaksom funkcija povratnih poziva i lambda izraza (budući da je u pitanju sintaksa koju treba temeljno poznavati - ukoliko planirate da koristite Javascript 'na duže staze' :)).

every

Naveli smo već da je sintaksa funkcija višeg reda uglavnom relativno jednostavna, * što možemo ilustrovati na primeru funkcije every (koja pristupa svakom elementu niza i poziva 'funkciju za obradu'):

		
// Opšta šema:
niz.every(funkcija_za_obradu)

// Funkcija every pristupa svakom elementu
// niza i primenjuje "funkciju za obradu"
// zarad provere uslova

// "Izolovani" primer:
niz.every(e => e > 1)
// e - pojedinačni element niza;
// funkcija every pristupa (redom) -
// svim elementima, i proverava,
// preko pomoćne lambda funkcije,
// da li je svaki element veći od 1

// Praktičan primer upotrebe:
if (niz.every(e => e > 1)) {
	console.log("Svi su veći od 1.")
}
		
	
Slika 18. - Funkcija every, koja proverava da li svaki element niza zadovoljava određeni kriterijum.

Funkcija every vraća vrednost true pod uslovom da svi elementi niza zadovoljavaju određeni uslov, dok je u suprotnom povratna vrednost false (u gornjem primeru, ispituje se da li su svi elementi niza veći od 1).

Sa jedne strane, kod deluje intuitivno (nadamo se :)), međutim, budući da (ipak) nisu u pitanju trivijalne ideje, potrudićemo se da odmah pojasnimo kako se navedeni kod interpretira.

Od svega je najbitnije razumeti da lambda notacija ** (kako u konkretnom primeru tako i inače), ne funkcioniše "sama od sebe", već, zato što je određena funkcija (u ovom slučaju funkcija every), osmišljena tako da "ispod haube" pristupa svim elementima niza - pri čemu koristi posebno definisanu "unutrašnju funkciju", ** koja je navedena u zagradi, preko koje se obavlja određena operacija (što u slučaju funkcije every znači - ispitivanje uslova).

* Bar je tako kada su u pitanju jednostavne/uobičajene lambda funkcije kakve prikazujemo. :)

** Lambda funkcija koju smo koristili u gornjim primerima definisana je tako da kao argument prima brojčanu vrednost i vraća logičku vrednost true pod uslovom da je uneti broj veći od 1 (pri čemu je "uokvirujuća" funkcija every (kao što smo već naveli), definisana tako da redom uzima u obzir sve elemente niza).

Još jednostavnije, "lambda" funkcija koja stoji 'u zagradi' ....

			
e => e > 1
			
		
Slika 19. - Primer izdvojene lambda funkcije.

.... predstavlja ekvivalent sledeće "imenovane" funkcije ....

			
function daLiJeVeciOdJedan(e) {
	return e > 1
}
			
		
Slika 20. - Primer imenovane funkcije koja odgovara lambda funkciji sa slike #19.

.... a ako (u nekom drugom slučaju) definišemo imenovanu funkciju, i ukoliko procenimo da je takav pristup 'zgodniji', takođe možemo i imenovanu funkciju koristiti u okviru metoda every, some i sl:

			
niz.every(daLiJeVeciOdJedan)
			
		
Slika 21. - Naredba sa slike #18 - prepravljena tako da koristi imenovanu funkciju (sa slike #20) umesto lambda funkcije.

some

Sledeći kod (po mnogo čemu sličan primerima iz prethodnog odeljka) ....

		
niz.some(e => e > 10)
		
	
Slika 22. - Funkcija some, koja proverava da li bar jedan element niza zadovoljava određeni kriterijum.

.... vraća vrednost true pod uslovom da je bar jedan element niza veći od 10 (u suprotnom, povratna vrednost je false).

map

Ukoliko je potrebno kopirati niz, pri čemu se novim elementima dodeljuju određene vrednosti preko funkcije, može se koristiti sledeća sintaksa:

		
let niz_a = [ 1, 2, 3, 4, 5 ];
let niz_b = niz_a.map(e => e * e);
		
	
Slika 23. - Funkcija map, koja kreira kopiju niza prema pravilu koje je određeno unutrašnjom funkcijom.

Pokretanjem skripte, nastaje novi niz: [ 1, 4, 9, 16, 25 ].

Nove vrednosti predstavljaju kvadrate vrednosti iz ulaznog niza, i pri tom se funkcija preko koje se definišu nove vrednosti (i ovoga puta) predaje kao argument, u zagradi.

filter

Ukoliko je pri kopiranju niza potrebno ukloniti određene vrednosti, koristi se funkcija filter.

Cela operacije podrazumeva kreiranje novog niza, u koji će biti kopirane samo vrednosti koje zadovoljavaju uslov:

		
let niz_a = [ 1, 2, 3, 4, 5 ];
let niz_b = niz_a.filter(e => e > 3);
		
	
Slika 24. - Funkcija filter, koja u novi niz kopira samo određene elemente, shodno uslovu.

U primeru sa gornje slike, novi niz sadržaće samo elemente 4 i 5 (to jest, kopiraju se samo vrednosti koje su veće od 3).

forEach

Za pojednostavljeni zapis petlje koja prolazi kroz ceo niz, JavaScript omogućava korišćenje konstrukcije forEach.

Opšta šema poziva funkcije forEach ima sledeći oblik ....

		
niz.forEach(element => {
	// naredbe za obradu
	// izdvojenog elementa
})
		
	
Slika 25. - Opšta šema izvršavanja metode forEach.

Pod uslovom da poziv forEach stoji uz određenu iterabilnu strukturu (niz, mapa i sl), funkcija će redom proći kroz sve elemente date strukture, i pozvati "unutrašnju" lambda funkciju za svaki element.

Navedene smernice najbolje ćemo razumeti ako se poslužimo primerom u kome se metoda forEach koristi za ispis (svih) elemenata niza koji su veći od 0 ....

		
let niz = [ 1, 2, 3, 4, 5 ];

niz.forEach(element => {
	if (element < 0) return;
	console.log(element);
});

// Ekvivalentna for petlja:

for (let i = 0; i < niz.length; ++i) {
	let element = niz[i];
	if (element < 0) break;
	console.log(element);
}
		
	
Slika 26. - Primer korišćenja funkcije forEach za ispis svih elemenata niza.

.... pri čemu se može primetiti da se elementima ne pristupa preko indeksa, već preko reference element (s tim da je u pitanju proizvoljno izabran identifikator, to jest, nije u pitanju rezervisana reč i sl). *

Za sam kraj, ostavili smo funkciju za sortiranje nizova, ** koja je u idejnom smislu jednostavna, ali - u velikoj meri zavisi od povratnih poziva i lambda izraza.

* I ovoga puta sintaksa deluje prilično intuitivno, međutim (iako na prvi pogled izgleda kao petlja), forEach nije petlja, već funkcija koja pokreće lambda funkciju (što možemo prepoznati, između ostalog, i po tome što se za prekid "ciklusa" ne koristi rezervisana reč break, već return, a postoje naravno i druge razlike).

** Funkcija za sortiranje nizova ponešto je komplikovanija za korišćenje, i stoga je naredna diskusija namenjena pre svega starijim i iskusnijim čitaocima (naravno, tematika može biti zanimljiva i ostalim čitaocima). :)

Sortiranje nizova (funkcija sort)

Kada je u pitanju uređivanje nizova brojčanih vrednosti u neopadajući ili nerastući poredak, može se primetiti da su programeri vrlo često skloni tome da samostalno implementiraju funkcije koje rešavaju navedene probleme (što svakako pozdravljamo).

Javascript takođe pruža mogućnost korišćenja ugrađene funkcije za sortiranje, međutim, bitno je odmah razumeti da je u pitanju funkcija koja, prema podrazumevanim podešavanjima (to jest, ako se ne preda ikakav argument), uređuje niz po abecednom redosledu. *

		
let niz_a = [ "Maja", "Ana", "Pera", "Mika" ];
niz_a.sort(); // [ "Ana", "Maja", "Mika", "Pera"]

let niz_b = [ 2, 10, 3, 5, 1, 6, 1, 4 ];
niz_b.sort(); // [ 1, 1, 10, 2, 3, 4, 5, 6]
		
	
Slika 27. - Uređivanje niza niski preko funkcije sort.

Da bi niz bio sortiran u nerastući poredak - prema brojčanim vrednostima (elemenata), potrebno je da se funkciji sort u svojstvu argumenta preda - funkcija.

Osnovni princip je sličan primerima iz prethodnih odeljaka, ali, tehnikalije su ponešto kompleksnije - i stoga ćemo se detaljnije pozabaviti lambda funkcijom koja se koristi u okviru funkcije sort.

U funkcijama za sortiranje nizova, često se javlja 'motiv' poređenja dva elementa niza, čije vrednosti potom treba (ili ne treba) razmeniti ....

		
function selectionSort(niz) {
    for (let i = 0; i < niz.length - 1; ++i) {
        let i_min = i;
		let min   = niz[i];

        for (let j = i + 1; j < niz.length; ++j) {
            if (niz[j] < min) { // poređenje
                i_min = j;
				min   = niz[j];
            }
        }

        if (i_min != i) {
            let p      = niz[i];
            niz[i]     = niz[i_min];
            niz[i_min] = p;
        }
    }
}
		
	
Slika 28. - Primer jednostavne ("školske") funkcije za sortiranje nizova.

.... a sam uslov za razmenu dva elementa (kao što možemo videti u gornjem primeru), zapisan je u telu funkcije - što praktično znači da se ne može menjati tokom izvršavanja programa ("tako je inače").

Prikazali smo primer prilično neefikasne funkcije za sortiranje nizova (algoritam "selection sort"), ali, primer dovoljno dobro 'potcrtava poentu'.

Shodno prethodnim uputstvima, nije teško pretpostaviti da je svrha lambda funkcije koja se funkciji sort predaje u svojstvu argumenta - odlučivanje u vezi sa tim da li će elementi niza koji se porede biti međusobno razmenjeni (ili neće).

Ako napravimo sledeći poziv (uz korišćenje pomoćne funkcije provera, koju ćemo samostalno implementirati) ....

		
function provera(a, b) {
	return a - b;
}

let niz = [ 2, 10, 3, 5, 1, 6, 1, 4 ];
niz.sort(provera) // 1, 1, 2, 3, 4, 5, 6, 10
		
	
Slika 29. - Sortiranje niza u neopadajući poredak, preko ugrađene funkcije sort.

.... niz će biti sortiran u neopadajući poredak - prema brojčanim vrednostima.

Za sortiranje niza brojčanih vrednosti u nerastući poredak, biće dovoljno da funkciju provera implementiramo na drugačiji način:

		
function provera(a, b) {
	return b - a;
}

let niz = [ 2, 10, 3, 5, 1, 6, 1, 4 ];
niz.sort(provera); // 10, 6, 5, 4, 3, 2, 1, 1
		
	
Slika 30. - Sortiranje niza u nerastući poredak preko ugrađene funkcije sort.

Naravno, postavlja se pitanje: kako program zapravo odlučuje da li će doći do razmene (a postavljaju se i pitanja oko toga kako dve funkcije 'sarađuju').

U funkcijama sa kojima smo se upoznali na početku poglavlja (every, some i dr), postojala je petlja koja prolazi redom kroz sve elemente, dok, kada je u pitanju funkcija sort, postoji kompleksnija struktura petlji preko kojih se elementi porede, * međutim, umesto unapred zadatih uslova (kao u primeru sa slike #28), koristi se pomoćna lambda funkcija: ukoliko funkcija za proveru vrati negativan broj (pri proveri određena dva elementa) - doći će do razmene, a ukoliko funkcija vrati nenegativan broj - neće doći do razmene.

U prvom slučaju (iz gornjih primera), do razmene dolazi ako je argument b veći, dok u drugom slučaju do razmene dolazi ukoliko je veći argument a.

Preko lambda notacije, pozivi se mogu dodatno uprostiti:

		
niz.sort((a, b) => a - b) // uređivanje niza u neopadajući poredak
niz.sort((a, b) => b - a) // uređivanje niza u nerastući poredak
		
	
Slika 31. - Pozivi funkcije sort za uređivanje brojčanih nizova - implementirani preko lambda notacije.

Funkcija sort može dobro poslužiti za sortiranje nizova manjeg obima, dok, kada je u pitanju sortiranje većih nizova, preporučujemo ('i dalje'), korišćenje funkcija koje ćete implementirati sami.

* Kada je u pitanju konkretan algoritam koji stoji 'iza' funkcije sort, možemo reći da izbor algoritma zavisi od sadržaja niza (slično kao što detalji same implementacije nizova zavise od JS endžina).

Ni ovoga puta nećemo previše ulaziti u detalje, ali, najčešće je u pitanju algoritam Quick Sort, sa tipičnom složenošću O(nlogn).

Da se podsetimo (još jednom/"za svaki slučaj"): sve što smo naveli i prikazali u vezi sa povratnim pozivima i lambda izrazima u ugrađenoj funkciji sort, moguće je izvesti samo zato što je funkcija sort projektovana tako da može na poseban način pokretati (druge) funkcije koje se predaju u svojstvu argumenata, a pre nego što se 'odjavimo', navešćemo i jednu napomenu preko koje ćemo 'postaviti stvari u perspektivu' (pre svega zarad čitalaca koji se tek upoznaju sa tematikom).

Naime, iako su kodovi koje smo prikazali prilično intuitivni (i mnogi čitaoci su verovatno već stekli prilično jasnu predstavu o tome kako se lambda notacija može koristiti), obim gradiva koje je prikazan u članku o funkcijama za obavljanje operacija sa nizovima u JS-u, ni iz daleka nije dovoljan za postizanje pravog razumevanja funkcija povratnog poziva i lambda notacije, i stoga preporučujemo da detaljnije proučite članak koji smo posvetili navedenim temama (naravno, onda kada dođe vreme). :)

Kratak rezime ....

Na kraju, može se (ipak :)) zaključiti da obavljanje operacija sa nizovima u JS-u nije nikakav "bauk".

Biće potrebno vreme (da 'pohvatate konce'), biće potrebno malo više pažnje (u odnosu na tipizirane jezike, u kojima postoje određeni mehanizmi koji sprečavaju 'nepodopštine i marifetluke', kao što je pokušaj dodavanja znakovne niske u niz celobrojnih vrednosti i sl), ali - ukoliko se potrudite - verujemo da ćete se u svemu snaći sasvim uspešno, i dobri rezultati neće izostati.

Sledeći članak o JS-u, posvetićemo implementaciji čvorova i struktura podataka ....

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > Operacije sa nizovima u programskom jeziku JavaScript
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt