Sintaksa
Arrow funkcija ili tzv.“fat arrow” je nova sintaksa za pisanje JavaScript funkcija. Najbitnija karakteristika arrow funkcije je kraća sintaksa koja implicira bolju preglednost. U zavisnosti od broja parametra i tela funkcije sintaksa ima više različitih načina pisanja koda:.
a) Izgled sintakse kada telo funkcije ima više izraza
Kod ovog slučaja sintaksa arrow funkcije je najsličnija običnoj funkciji, a jedina razlika se dobija pri ukidanju ključne reči “function” a dodavanjem “fat arrow”. Ova sintaksa se koristi kada u telo funkcije ima više izraza:
1 2 3 4 5 6 7 8 9 10 11 |
//ES5 var multiply = function(x, y) { var tekst = "Ovo je funkcija"; console.log(tekst); }; //ES2105 var multiply = (x, y) => { var tekst = "Ovo je funkcija"; console.log(tekst) }; |
b) Izgled sintakse kada telo funkcije ima jedan izraz
Ukoliko telo ima samo jedan izraz koji je vraćen sa “return” onda možemo da izbacimo i vitičaste zagrade i rezervisanu reč “return”:
Primer
1 2 3 4 5 6 7 8 |
//ES5 var multiply = function(x, y) { return x * y; }; //ES2105 var multiply = (x, y) => x * y; |
c) Izgled sintakse kada se funkciji ne prosledjuju parametri
Ako se funkciji ne prosledjuju parametri onda moraju da postoje prazne zagrade () u delu rezervisanom za parametre funkcije
1 2 3 4 5 6 7 |
// ES5 var stampa = function () { console.log ("Stampa iz obične funkcije"); } //ES2105 var stampa2 = () => {console.log("Stampa iz arrow funkcije")}; |
d) Izgled sintakse kada se fukciji prosledjuje samo jedan parametar
Ukoliko se funkciji prosedjuje samo jedan parametar onda možemo da izbacimo i zagrade oko parametara:
Primer
1 2 3 4 5 6 7 |
//ES5 var duplo = function(x) { return x * 2; } //ES2105 var duplo = x => x * 2; |
Prednost nove sintakse se još bolje vidi kada koristimo nove metode za iteraciju nada nizovima:
Primer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
var niz = [1,2,3]; // ES5: var duplo = function(x) { var noviNiz = []; for (var x of niz) { noviNiz.push(x*2); }; return noviNiz; } console.log(duplo(niz)); // ES2105 bez arrow funkcije: var noviNiz = niz.map (function (clan){ return clan * 2; }); console.log(noviNiz); // ES2015 var noviNiz = niz.map ( clan => clan*2 ); console.log(noviNiz); |
e) Izgled sintakse kada vraća “Object Literal”
Vraćanje objeknogt literala sa ES5 sintaksom izgleda ovako:
1 2 3 |
var kvadrat = function(n) { return { kvadratBroja: n * n }; }; |
Prema dosadašnjim pravilima prethodni zadatak sa arrow funkcijom bi izgledao ovako:
1 |
let kvadrat = n => { kvadratBroja: n * n }; // Vraća: undefined |
Medjutim ovakava sintaksa nije dobra, a funkcija vraća undefined, jer parser vitičaste zagrade prepozanje kao telo funkcije a ne kao objekt literal. Stoga po njemu sintaksa sa dvotačkom u telu funkcije nije dobra. Da bi parser prepozanao da je u pitanju ES6 sintaksa potrebno je oko objektnog literala staviti obične zagrade:
1 2 |
let kvadrat = n => ({ kvadratBroja: n * n }); console.log(kvadrat(5)); // Vraća: {kvadratBroja: 25} |
Domen ključne reči “this”
Arrow function umesto da primenjuje neko od 4 standardna pravila za povezivanje this, ona sasvim zaobilazi standardni mehanizam i povezuje this sa okružujućim opsegom vidljivosti (leksički opseg vidljivosti). Kod pozivanja ovih funkcija this nasledjuje značenje this iz okružujuće funkcije. Uprošteno this arrow funkcije se izjednačava sa onim na šta bi ukazivalo this iz spoljne funkcije koja okružuje arrow funkciju (ona unutar sebe ima ugradjen engine koji praktično zamenjuje poznati mehanizam: “self=this”). Kada se koristi arrow funkcija nije bitan način i mesto pozivanja funkcije, već samo na šta ukazuje this iz spoljne funkcije.
NAPOMENA:
Značenje koje je operator this dobio unutar arrow funkcije se ne može kasnije promeniti! Tako da ne može biti pregaženo ni sa predefinisanim metodama bind(), apply() ili call() pa čak ni sa operatorom “new”.
Primer – Problem sa closure
Poznat je problem kada clousure funkcija unutar objekta “izgubi” referencu na taj objekta: :
1 2 3 4 5 6 7 8 9 10 11 12 |
var osoba = { ime:"Pera", prezime: "Peric", punoIme: function () { //this funkcije punoIme() ukazuje na objekat "osoba" var spajanjeImena = function(){ console.log(this.ime + " " + this.prezime); //this funkcije spajanjeImena() ukazuje na globalni objekat }; return spajanjeImena(); } }; osoba.punoIme(); // Vraca undefined |
Rezervisan reč “this” u okviru clousure funkcije spajanjeImena() je izgubila referencu na objekat osoba i ukazuje na globalni objekat. Ovaj problem se može rešiti korišćenjem arrow funkcije, jer će njeno značenje rezervisane reči “this” biti izjednačeno sa značenjem this iz okružujuće funkcije. U ovome slučaju okružujuća funkcija je punoIme(), i ukazuje na objekat osoba. Pa će i this unutar arrow funkcije takodje ukazivati na objekat “osoba”.
1 2 3 4 5 6 7 8 9 10 11 12 |
var osoba = { ime:"Pera", prezime: "Peric", punoIme: function () { console.log(this); //this funkcije punoIme() ukazuje na objekat "osoba" var spajanjeImena = () => { console.log(this.ime + " " + this.prezime); //this funkcije spajanjeImena() ukazuje na objekat "osoba" }; return spajanjeImena(); } }; osoba.punoIme(); // Pera Perić |
Kada koristiti arrow funkciju?
Arrow funkciju ne treba koristiti uvek tj. kao totalnu zamenu za klasičnu deklaraciju funkcije. Postoje slučajevi kad arrow funkcija “zasija” punim sjajom, ali takodje postoje slučajevi kada jednostavno ne može da se koristi.
Preporuka za korišćenje arrow funkcije
Generalno je preporuka da se arrow funkcija koristi kada imamo jednostavne funkcije sastavljene od jednog iskaza, gde je jedini iskaz return ili neka izračunata vrednost a fa se u okviru tela funkcije ne koristi “this”, osim ako nije u pitanju closure.
Primer
1 |
[1,2,3].map(x => 2 * x) |
Slučajevi kada treba izbegavati arrow funkciju
Arrow funkciju ne treba koristiti:
- a) Ako se u okviru metode objekta koristi rezervisana reč “this” (ovaj stav ne važi za closure, jer tada je poželjno koristiti arrow funkciju), jer “this” tada ukazuje na globalni objekat
123456function MyCat(name) {this.catName = name;}MyCat.prototype.sayCatName = () => {return this.catName; // "this" ukazuje na "window" pa je "this.catname" undefined}; - b) Ako je u pitanju dinamički kontekst, kao što je callback funkcija u okviru EventListener-a, jer “this” ne ukazuje na objekat na koji je zakačen listener nego na globalni objekat:
1234var button = document.getElementById('myButton');button.addEventListener('click', () => {this.innerHTML = 'Dugme je već kliknuto'; // "this" ukazuje na globalni objekat a ne na button}); - c) U okviru konstruktorske funkcije, jer “this” bi trebalo da ukazuje na novo generisan objekt:
1234var Message = (text) => {this.text = text;};var helloMessage = new Message('Hello World!'); // Throws "TypeError: Message is not a constructor" - d) Kada je u funkciji potreban “arguments” objekat, jer kada koristimo arrow funkciju nemamo pristup “arguments” objektu.
Dragoljube, hvala na ovom detaljnom objašnjenju,
pretražio sam mnoge sajtove i preslušao mnoga YT objašnjenja na temu Arrow i this keyworda ali nigde nije lepo objašnjeno kao ovde, sve na jednom mestu! Tek sada sam skapirao kako funkcioniše this u okviru arrow i obične funkcije.
Hvala i pozdrav!
Hvala Adame na lepim rečima.