nav_dugme codeBlog codeBlog
  • početna
  • Učionica
  • Saveti
  • Zanimljivosti
  • Kontakt

Javascript ES6 sintaksa

Viber
zoom_plus zoom_minus

Uvod

Svako ko se malo duže bavi programiranjem, svestan je ogromne popularnosti koju JavaScript kao jezik, uživa u ovom trenutku.

Ovaj jezik, svoj život je započeo kao skriptni jezik za pristup DOM elementima u web browserima (naravno, i danas obavlja navedenu ulogu), ali je tokom vremena - pogotovo u poslednjih šest, sedam godina - prevazišao početne okvire i postao osnova velikog broja krajnje zanimljivih radnih okruženja (pre svih, node.js, pa zatim i Angular, React, Vue.js, Express ...), koja zajedno čine svojevrstan "ekosistem" za razvoj, pre svega web aplikacija, ali i desktop aplikacija, kao i raznovrsnih biblioteka i dodataka.

Kada je u pitanju razvojni put programera koji su savladali osnove JS-a i žele da se usmere na prethodno navedene tehnologije, koje nude velike mogućnosti razvoja individualne programerske veštine, kao i brojne prilike za rad na izazovnim i zanimljivim projektima, postavlja se pitanje: šta su najvažnije tehnike koje prethodno treba savladati.

Ako nas pitate, u pitanju su upravo unapređenja koja su došla sa revizijom jezika ECMAScript 2015 (odnosno ECMAScript 6, ili, još jednostavnije - ES6), za koja ćemo u daljem tekstu koristiti opšteprihvaćeni naziv - ES6 sintaksa.

ES6 sintaksa - najvažniji elementi

Nećemo nabrajati sva unapređenja koja su došla sa revizijom ES6, koja se pojavila 2015. (od kada popularnost JS-a zapravo i beleži najveći napredak) i nećemo previše ulaziti u detalje, ali ćemo napraviti izbor najznačajnijih i, slobodno možemo reći - krajnje neophodnih tehnika, za sve one koji žele da se ozbiljnije pozabave Node.js aplikacijama, ili razvijaju sajtove u nekom od popularnih "framework-a", kao što su React, Angular, Vue, ili Express.

U tom smsilu, ovaj članak biće svojevrstan informator za sve programere koji imaju takve namere (a pri tom, već imaju iza sebe neophodno predzanje i određeno iskustvo), ali i svojevrsna rekapitulacija tehnika koje su deo ES6 sintakse, a kojima smo već posvetili detaljne članke, pri čemu će biti reči i o tehnikama koje do sada u člancima nismo spominjali (moduli, destrukturiranje elemenata).

Najvažnijim unapređenjima koje je donela ES6 sintaksa, smatramo arrow funkcije, šablonske niske i promise, ali, krenućemo od nečeg osnovnijeg ....

Novi način označavanja promenljivih - let i const

Možemo reći da stari način definisanja promenljivih preko rezervisane reči var uglavnom (ipak) nije zadavao prevelike probleme programerima, ali, svakako je imao nedostatke.

Pre svega:

  • nije bilo moguće definisati konstante
  • nije bilo moguće definisati promenljive koje su definisane samo unutar bloka programskog koda (block scope)

Deklaracija podataka preko rezervisanih reči const i let, otklanja navedene nedostatke i proširuje mogućnosti:

const

Kada pri deklaracije podatka, koristimo rezervisanu reč const, deklarisani podatak ima sledeće osobine:

  • mora se inicijalizovati odmah pri deklaraciji
  • nije moguće naknadno menjati vrednost
  • ako se deklaracija pojavi unutar bloka (između vitičastih zagrada), dati blok koda predstavlja opseg definisanosti podatka

Poslednja stavka je bitna i zanimljiva, jer promenljive definisane preko rezervisane reči var prepoznaju samo globalni opseg i opseg funkcije.

Kada su u pitanju nizovi i objekti, stvari su malo komplikovanije (ali, i dalje razumljive). Kod podataka deklarisanih preko rezervisane reči const, "konstantna" je referenca na objekat, dok se stanje objekta može menjati, ali, bez naknadnog pozivanja naredbe dodele (recimo, objektima možemo menjati vrednosti polja, nizovima dodavati i uklanjati elemente i slično).

Moglo bi se reći da isti princip važi, i za osnovne tipove podataka (int, char, float), i za nizove i objekte, samo što osnovnim tipovima ne možemo promeniti "stanje", bez pozivanja naredbe dodele.

Na sledećoj slici vidimo primere koji pokazuju šta se može, a šta ne može, raditi sa podacima deklarisanim preko rezervisane reči const:

		
// Inicijalizacija se mora obaviti u istoj naredbi sa deklaracijom:

const PI = 3.14159265359; // OK

const g;  // GREŠKA!
g = 9.81; // GREŠKA!

// Inicijalizovanim nizovima mogu se dodavati i uklanjati elementi,
// ali se referenca na niz ne sme menjati:

const niz = [1, 2, 3, 4]; // OK
niz.push(5);              // OK
niz = [2, 3, 7, 13]       // GREŠKA!

// Vrednosti polja objekata mogu se menjati, ali se ne sme menjati
// referenca (tj. ne sme se naknadno koristiti naredba dodele):

const osoba = {
	ime:     "Petar",
	prezime: "Milinković"
}                         // OK

osoba.ime = "Marija"      // OK

osoba = {
	id:     1,
	uid:    korisnikX,
	status: admin
}                         // GREŠKA!

// Deklaracija preko rezervisane reči const poštuje
// opseg bloka uokvirenog vitičastim zagradama:

{
	const p = "Proba";
	console.log(p);       // OK
}

console.log(p);           // GRESKA!
		
	
Slika 1. - Primeri dozvoljenih i nedozvoljenih operacija sa podacima deklarisanim preko rezervisane reči const.

let

Promenljive deklarisane preko rezervisane reči let, imaju sledeće osobine:

  • može im se menjati vrednost naknadno, ali se ne smeju ponovo deklarisati
  • vrednost promenljive može se menjati naknadno
  • inicijalizacija se ne mora obaviti pri deklaraciji
  • ako se deklaracija pojavi unutar bloka (između vitičastih zagrada), dati blok koda predstavlja opseg definisanosti promenljive

Ponovo ćemo pogledati primer koji prikazuje navedeno:

		
// Inicijalizacija se može, ali i ne mora,
// obaviti u istoj naredbi sa deklaracijom:

let PI;             // OK
PI = 3.14159265359; // OK

// Inicijalizovanim nizovima mogu se dodavati i uklanjati elementi,
// a može se koristiti i naredba dodele nakon inicijalizacije:

let niz = [1, 2, 3, 4]; // OK
niz.push(5);            // OK
niz = [2, 3, 7, 13]     // OK

// Vrednosti polja objekata mogu se menjati, a može se
// naknadno koristiti i naredba dodele:

let osoba = {
	ime:     "Petar",
	prezime: "Milinković"
}                         // OK

osoba.ime = "Marija"      // OK

osoba = {
	id:     1,
	uid:    korisnikX,
    status: admin
}                         // OK

// Deklaracija preko rezervisane reči let poštuje
// opseg bloka uokvirenog vitičastim zagradama:

{
	let p = "Proba";
	console.log(p);       // OK
}

console.log(p);           // GRESKA!
		
	
Slika 2. - Primer dozvoljenih i nedozvoljenih operacija sa promenljivama deklarisanim preko rezervisane reči let.

Arrow funkcije

Arrow funkcijama, kao specifičној implementaciji lambda izraza u JavaScript-u, posvetili smo veliki deo članka o lambda izrazima, pa se ovoga puta nećemo previše zadržavati na detaljima, ali, ponovimo najvažnije:

u pitanju je način da se imenovana funkcija (koja je, za određene potrebe, možda previše "zvanična"), zapiše na jednostavniji način:

Ako krenemo od funkcije koja vraća veću od dve unete vredosti

		
function veciOdDva(a, b) {
	return (a > b)? a: b;
}	
		
	
Slika 3. - Standardna imenovana funkcija koju ćemo pretvoriti u lambda funkciju.

.... izostavićemo rezervisanu reč funciton, kao i naziv funkcije, i potom izmeću parametara i tela funkcije dodati lambda operator =>:

		
(a, b) => {
	return (a > b)? a: b;
}	
		
	
Slika 4. - Pretvaranje imenovane funkcije u lambda funkciju - korak 1.

Budući da funkcija ima samo jednu naredbu (koja pri tom sadrži rezervisanu reč return), možemo funkciju dodatno pojednostaviti:

  • izostavićemo vitičaste zagrade
  • izostavvićemo rezervisanu reč return
  • telo funkcije zapisaćemo u jednom redu
		
(a, b) => (a > b)? a: b
		
	
Slika 5. - Pretvaranje imenovane funkcije u lambda funkciju - korak 2.

Sve to jako dobro dođe u povratnim pozivima i pri tom (što i jeste ideja koja stoji iza ovakvog zapisa i njegova glavna svrha), deluje jako elegantno.

Na primer, umesto imenovane funkcije:

		
function kvadrat(x) {
	return x * x;
}

let niz1 = [1, 2, 3, 4, 5];
let niz2 = niz1.map(kvadrat);
		
	
Slika 6. - Mapiranje niza preko imenovane funkcije.

.... ili standardne neimenovane funkcije:

		
let niz1 = [1, 2, 3, 4, 5];
let niz2 = niz1.map(function() {
	return x * x;
});
		
	
Slika 7. - Mapiranje niza preko neimenovane funkcije.

.... koristićemo arrow funkciju:

		
let niz1 = [1, 2, 3, 4, 5];
let niz2 = niz1.map(x => x * x);
		
	
Slika 8. - Mapiranje niza preko arrow funkcije.

Ni u kom slučaju ne možemo reći da je programski kod u prva dva primera nezgrapan i neelegantan (sam po sebi), ali, ako bismo bili hteli da "bušimo dlaku iznutra po dužini i urezujemo unutrašnji navoj" (obično "cepidlačenje" nije dovoljno za programere sa izvesnim stažom), rekli bismo sledeće:

  • kod u prvom slučaju je u redu, pod uslovom da nam je funkcija kvadrat potrebna i za druge namene (da nije napisana samo zarad povratnog poziva)
  • kod u drugom primeru je pomalo neelegantan

.... ali, samo u poređenju sa lambda funkcijama koje deluju "kao stvorene" za ovakve namene (jer, kao što rekosmo, doslovno jesu stvorene za ovakve namene).

Arrow funkcije (očigledno) predstavljaju veoma efektno rešenje koje je široko rasprostranjeno u standardnim web aplikacijama koje koriste Javascript, kao i Node.js aplikacijama.

Šablonske niske

Šablonske niske (pattern literals) su obrasci za spajanje teksta sa vrednostima promenljivih i izraza koji su definisani između `` ("backtick") znakova.

Na primer, sledeći kod ....

		
let a = 5, b = 10;
let s = `Zbir brojeva ${a} i ${b} je ${a + b}`
console.log(s);
		
	
Slika 9. - Primer jednostavne šablonske niske.

.... u konzoli će ispisati:

		
Zbir brojeva 5 i 10 je 15
		
	
Slika 10. - Ispis koda sa prethodne slike.

Ili, malo konkretniji primer (nalik na primerima koji se svakodnevno koriste kroz React, Angular ili Vue.js)

		
let paketPodataka = {
	naslov: "Šablonske niske",
	tekst:  "Šablonske niske omogućavaju umetanje vrednosti promenljivih i izraza u tekst"
}

function formatiranjeHTMLElementa(paket) {
	return 
`
<h2>${paket.naslov}</h2>
<p>
	${paket.tekst}
</p>`;
console.log(formatiranjeHTMLElementa(paketPodataka));
}
		
	
Slika 11. - Primer šablonske niske za formatiranje HTML elementa.

Promisi

Za razliku od lambda / arrow funkcija koje (makar čitaocima sa prethodnim iskustvom), lako možemo predstaviti u nekoliko reči, sa promisima to nije slučaj (ali, pokušaćemo).

Ukratko (i pre svega), u pitanju je način da se lanac funkcija (gde izvršavanje određene funkcije zavisi od rezultata prethodne), umesto na sledeći način ....

		
setTimeout(() => {
	if(!f1()) return new Error("Funkcija f1 nije se izvršila pravilno"):
	setTimeout(() => {
		if(!f2()) return new Error("Funkcija f2 nije se izvršila pravilno"):
		setTimeout(() => {
			if(!f3()) return new Error("Funkcija f3 nije se izvršila pravilno"):
			setTimeout(() => {
				if(!f4()) return new Error("Funkcija f4 nije se izvršila pravilno"):
				setTimeout(() => {
					if(f5()) {
						console.log("Čestitamo, uspeli ste!");
					}
					else {
						console.error("Gre'ota! Niste imali sreće na samom kraju!")
					}
				}, INTERVAL_5);
			}, INTERVAL_4);
		}, INTERVAL_3);
	}, INTERVAL_2);
}, INTERVAL_1);
		
	
Slika 12. - Ugnježđeni povratni pozivi funkcija - "callback hell".

.... zapiše mnogo preglednije:

		
f1()
	.then(f2)
	.then(f3)
	.then(f4)
	.then(f5)
	.then(rez     => krajnjaObrada(rez))
	.catch(greska => obradaGreske(greska));
		
	
Slika 13. - Primer korišćenja promisa koji se koristi umesto zapisa sa prethodne slike.

Kada su promisi u pitanju, sa standardom ES7 (iz 2017.) došla je i async / await sintaksa (pri čemu ćemo biti praktični i pomenuti je, iako očigledno nije deo ES6 standarda):

		
try {
	let rez1 = await f1();
	let rez2 = await f2(rez1);
	let rez3 = await f3(rez2);
	let rez4 = await f4(rez3);
	let rez5 = await f5(rez4);
	krajnjaObrada(rez5);	
}
catch (greska) {
	obradaGreske(greska);
}
		
	
Slika 14. - Promis sa prethodne slike, zapisan preko async / await sintakse.

Rad sa modulima

U velikim projektima, kada se javi potreba za podelom koda na manje celine, možemo kod podeliti u zasebne datoteke, a potom, preko rezervisane reči export, omogućiti da elovi koda iz određene JS datoteke postanu dostupni ostalim datotekama.

Na primer, funkcije iz datoteke funkcije.js ....

		
export function Obim(a, b) {
	return 2 * a + 2 * b;
}

export function Povrsina(a, b) {
	return a * b;
}
		
	
Slika 15. - JS datoteka u kojoj se poziva komanda export.

.... možemo importovati i koristiti u drugoj datoteci:

		
import { Obim, Povrsina} from './funkcije';

console.log(Obim(5, 10));     // 30
console.log(Povrsina(5, 10)); // 50
		
	
Slika 16. - Import funkcija iz datoteke sa prethodne slike.

Destrukturiranje elemenata

Destrukturiranje elemenata dozvoljava veoma zanimljiv način pristup elementima koji se nalaze unutar objekata i nizova.

Na primer, ako je objekat definisan na sledeći način:

		
let osoba = {
	ime: "Petar",
	prezime: "Petrović"
}
		
	
Slika 17. - Primer objekta koji čemo koristiti za destrukturiranje.

... možemo ga (po potrebi) destrukturirati:

		
let { ime, prezime } = osoba;

console.log(ime);     // Petar
console.log(prezime); // Petrović
		
	
Slika 18. - Destrukturiranje objekta sa prethodne slike.

Ili, u slučaju niza:

		
let niz = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let {prvi, dugi, treci, ...ostali} = niz;

console.log(prvi);   // 1
console.log(drugi);  // 2
console.log(treci);  // 3
console.log(ostali); // [4, 5, 6, 7, 8, 9, 10]
		
	
Slika 19. - Destrukruriranje niza.

Klase

Iako smo se klasama u Javascript-u već ranije bavili, spomenućemo ih ukratko i ovde, jer su uvedene upravo sa revizijom ES6.

Klasa definiše šablon za kreiranje objekta:

		
class Osoba
{
	constructor(ime, prezime)
	{
		this.ime     = ime;
		this.prezime = prezime;
	}
}
		
	
Slika 20. - Primer jednostavne klase.

.... koji se potom može instancirati:

		
let osoba = new Osoba("Petar", "Milinković");
		
	
Slika 21. - Instanciranje klase sa prethodne slike.

Podrazumevane vrednosti parametara funkcija

Počevši od revizije ES6, Javascript dozvoljava korišćenje podrazumevanih vrednosti za parametre funkcija (prepoznaju se po naredbi dodele):

		
function zbir(a, b = 15) {
	return a + b;
}

console.log(zbir(10, 12)); // 22
console.log(zbir(10));     // 25
		
	
Slika 22. - Primer funkcije koja koristi podrazumevanu vrednost.

Funkcije sa proizvoljnim brojem parametara

Ako funkciju deklarišemo na sledeći način:

		
function suma(....parametri) {
	let s = 0;
	for(let p of parametri) {
		s += p;
	}
	return p;
}
		
	
Slika 23. - Funkcija sa proizvoljnim brojem parametara.

.... moći ćemo da joj uputimo sledeći poziv:

		
console.log(sum(1, 2, 19, 74, 211)); // 307
		
	
Slika 24. - Poziv funkcije sa prethodne slike.

.... pri čemu vidimo da se predati argumenti tretiraju kao niz

Nove matematičke funkcije

Sa standardnom ES6, došle su i nove matematičke funkcije:

		
Math.cbrt(8);     // Kubni koren            - Math.cbrt(8)    == 2
Math.sign(-10);   // Znak broja             - Math.sign(-10)  == -1
Math.trunc(4.51); // Znak broja             - Math.sign(4.51) == 4
Math.log2(32);    // Logaritam za osnovu 2  - Math.log2(32)   == 5
Math.log10(100);  // Logaritam za osnovu 10 - Math.sign(100)  == 2
		
	
Slika 25. - Nove matematičke funckije iz revizije ES6.

Eksponencijalni operator

Za kraj, jedna sitnica, koja, iako ne predstavlja preveliko unapređenje, svakako dobro dođe.

Umesto da stepenovanje zapišemo na sledeći način ....

		
let a = 2 * 2 * 2 * 2;
		
	
Slika 26. - Eksponecnijalni operator koji je takođe uveden sa revizijom ES6.

.... naredbu koja računa četvrti stepen broja dva, sada možemo zapisati mnogo jednostavnije:

		
let a = 2 ** 4; // 16
		
	
Slika 27. - Primer upotrebe eksponencijalnog operatora.

Zaključak

Kao što smo već rekli, ovaj članak bio je kratka rekapitulacija i "usputna stanica" za one koji su odlučili da savladaju React, Vue ili Angular (ili neku od drugih popularnih i široko rasprostranjenih tehnologija), ali, sve tehnike o kojima smo pisali možemo posmatrati i nezavisno, kao veoma zanimljivu pojavu i deo jezika koji je često osporavan, ali je sa vremenom postajao sve bolji i bolji.

Posle upoznavanja sa ES6 sintaksom, otvaraju se brojni putevi (mi smo nabrojali samo neke, one najpopularnije) i, koji god da izaberete, želimo vam puno sreće u daljem razvoju!

Autor članka Nikola Vukićević Za web portal www.codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu www.codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta www.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.
©2021. Sva prava zadržana.
Viber
početna Početna > Članci > Javascript ES6 sintaksa

Info & povezani članci

Info

trejler_sat Datum objave: 08.07.2021.

trejler_dokument Jezici: JavaScript

trejler_teg_narandzasti Težina: 7/10

Povezani članci

Asinhrono programiranje u Javascript-u Callback funkcije i lambda izrazi Šablonske niske Uvod u Node.js Uvod u Fetch API Uvod u AJAX - Asynchronous Javascript And XML Uvod u Python ASCII, UNICODE i UTF-8 - Predstavljanje znakova na računarima Uvod u Javascript i DOM (Document Object Model) Kako napraviti web sajt - 1. deo - Početni koraci JSON - tekstualni format za predstavljanje objekata JSON Web Token
Preuzmite PDF verziju
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
John Woods
codeBlog codeBlog
Projekat posvećen popularizaciji kulture i veštine programiranja među mladim programerima.
Napomena: Tekstovi i slike na sajtu www.codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta www.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.
© 2021. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt