Funkcje strzałkowe
Funkcje strzałkowe pozwalają na krótszą deklarację funkcji. Do tej pory definicja funkcji mogła mieć dwie formy:
wyrażenia
const myNewFunction = function(x, y) {
return x + y
}
deklaracji
function myNewFunction(x, y) {
return x + y
}
Jaka jest między nimi różnica?
Kiedy przeglądarka napotyka deklarację funkcji to tworzy ją, po czym tworzy zmienną o takiej nazwie jak nazwa funkcji i przypisuje jej referencję do utworzonej wcześniej funkcji. W przypadku wyrażenia funkcyjnego to przeglądarka również tworzy funkcje i zwraca referencję do niej ale nie zapisuje jej w żadnej zmiennej. Oznacza to, że wyrażenie funkcyjne musi mieć miejsce zanim spróbujemy wywołać funkcję.
Brzmi skomplikowanie? Zobaczcie jak to wygląda w praktyce. Otwórzcie dowolną stronę internetową (np. girlsjs.pl). Następnie otwórzcie narzędzia developerskie i przejdźcie do zakładki Console. Wpiszcie tam:
mySum(2,4);
const mySum = function(x,y) {
return x + y
}
Użyliśmy funkcji zanim ją utworzyliśmy z wyrażenia. Dlatego pojawił nam się błąd.
Spróbujmy wykonać podobną operację z deklaracją funkcji:
mySum(2,4);
function mySum(x,y) {
return x+y
}
Funkcja wykonała się poprawnie mimo że została użyta przed jej deklaracją.
Gdzie te strzałki?
Jak wspomnieliśmy, ES6 umożliwia nam prostszy sposób definiowania funkcji. Wróćmy do wyrażenia:
const mySum = function(x,y) {
return x + y
}
Gdybyśmy chcieli zmienić ten zapis na funkcję strzałkową wyglądałaby ona tak:
const mySum = (x,y) => {return x+y}
Idźmy o krok dalej. Gdy mamy tylko jeden argument nie musimy go zapisywać w nawiasie:
const mySquared = x => {return x*x}
Gdy funkcja nie ma żadnego parametru zapisujemy pusty nawias:
const isWrong = () => {return "Some error"}
Przejdźmy na drugą stronę strzałki. Jeżeli nasza funkcja ma nam tylko zwracać jakąś wartość nie musimy używać klamrowych nawiasów:
const mySquared = x => x*x
Nawiasy klamrowe oznaczają blok. Wyobraźmy więc sobie, że chcemy zwrócić obiekt {name: "Tom", job: "JS Developer"}.
Gdy zapiszemy to w następujący sposób:
const newDev = () => {name: "Tom", job: "JS Developer"}
pojawi nam się informacja o błędzie.
Możemy oczywiście wrócić do dłuższego zapisu:
const newDev = () => { return {name: "Tom", job: "JS Developer"}}
Jednak funkcje strzałkowe pozwalają na skrócenie także takiej funkcji. Wystarczy obiekt umieścić w okrągłych nawiasach:
const newDev = () => ({name: "Tom", job: "JS Developer"})
Praktyka czyni mistrza
Pamiętacie nasze funkcje służące do losowej zmiany koloru tekstu? Wyglądała mniej więcej tak:
function getRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
const randomNumber = Math.floor(Math.random() * 16);
const randomLetter = letters[randomNumber];
color += randomLetter;
}
return color;
}
function changeColor(text) {
text.style.color = getRandomColor();
}
function makeMagic(text) {
setInterval(function() {
changeColor(text);
}, 2000);
}
Spróbujmy je przerobić na funkcje strzałkowe.
_"this" _is awesome!
Krótszy zapis to jednak nie jedyna zmiana, która przyszła wraz z wprowadzeniem funkcji strzałkowej. Ciekawsza jest zmiana kontekstu dla "this". Czym jest this?
Zacznijmy od prostego obiektu:
const person = {
name: "Tomasz",
lastName: "Nowak",
printFullName: function() {
console.log(this.name + " " + this.lastName)
}
}
Teraz wywołajmy funkcję dla naszego obiektu:
person.printFullName();
Następnie przeróbmy nasz obiekt i zapiszmy funkcję printFullName() w formie strzałkowej, następnie wywołajmy ją.
Pierwszy sposób zapisu wyświetlił w konsoli "Tomasz Nowak". Drugi sposób zapisu zwrócił "undefined". Dlaczego?
Spróbujmy sprawdzić co się kryje pod samym "this".
const person = {
name: "Tomasz",
lastName: "Nowak",
printFullName: function() {
console.log(this.name + " " + this.lastName)
},
printElement: function() {
console.log(this)
}
}
Następnie wywołajmy funkcję printElement:
person.printElement();
Funkcja zwróciła nam obiekt person. Co się stanie gdy przerobimy ją na funkcję strzałkową?
const person2 = {
name: "Tomasz",
lastName: "Nowak",
printFullName: () => {
console.log(this.name + " " + this.lastName)
},
printElement: () => {
console.log(this)
}
}
person2.printElement();
Tym razem funkcja zwraca nam obiekt window. Dlaczego? Przy klasycznym zapisie funkcji "this" wskazuje na obiekt, do którego dana metoda należy. W drugi przypadku wskazuje na zewnętrzny kontekst. Czy jest to pomocne?
Powiedzmy, że chcemy wyświetlić nazwisko naszego obiektu po kliknięciu klawisza ESC:
const person = {
name: "Tomasz",
lastName: "Nowak",
bindESC: function() {
document.body.addEventListener('keydown', function(e) {
if(e.keyCode === 27){
alert(this.name + " " + this.lastName)
}
});
}
}
person.bindESC();
Nie do końca się udało prawda? Wyświetlają się wartości undefined. Spróbujmy więc z funkcją strzałkową:
const person2 = {
name: "Tomasz",
lastName: "Nowak",
bindESC: function() {
document.body.addEventListener('keydown', (e) => {
if(e.keyCode === 27){
alert(this.name + " " + this.lastName)
}
});
}
}
person2.bindESC();
Tym razem wyświetliło poprawne wartości, prawda?