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?

results matching ""

    No results matching ""