Funkcje strzałkowe i callbacki
Jak przekazać programowi zasadę naliczania punktów? Przekaż funkcję. Strzałki pomogą Ci czytać map, filter i kod korzystający z callbacków.
Po tej lekcji potrafisz
- Zapiszesz funkcję strzałkową w dwóch wariantach.
- Przekażesz funkcję jako argument i opiszesz jej typ.
- Użyjesz map, filter i forEach, rozpoznając ich różne wyniki.
Tryb gry zmienia punktację
Dzisiaj punkty liczymy podwójnie, jutro z premią 5. Zamiast wpisywać warunki w każdej rundzie, możemy przekazać regułę jako funkcję. Callback to po prostu funkcja przekazana innemu fragmentowi kodu do wywołania.
Małe kroki, konkretne efekty
Strzałka w wersji krótkiej i z blokiem
Po lewej są parametry, po prawej działanie. Jedno wyrażenie po strzałce jest zwracane automatycznie. Jeśli otwierasz blok klamrami, wpisz return samodzielnie.
const podwoj = (n: number): number => n * 2;
const potroj = (n: number): number => {
return n * 3;
};
console.log(podwoj(4), potroj(4));8 12Przypisujemy funkcję do const, więc wywołujemy ją dopiero po tej deklaracji. To nie jest identyczne z deklaracją function, którą można wywołać wcześniej w jej zasięgu.
Funkcja jako argument
Typ (n: number) => number opisuje funkcję przyjmującą liczbę i zwracającą liczbę. Nawiasy przy regule w środku uruchamiają przekazaną funkcję.
function przelicz(n: number, regula: (n: number) => number): number {
return regula(n);
}
console.log(przelicz(10, n => n * 2));
console.log(przelicz(10, n => n + 5));20
15Nie dopisujemy typu przy drugim n: TypeScript odczytuje go z oczekiwanego typu parametru regula. To typowanie kontekstowe.
Tablica wyników po weekendowym bonusie
Najpierw zwiększamy wszystkie wyniki, potem wybieramy te uprawniające do nagrody. forEach służy wyłącznie do wypisania raportu.
const wyniki = [5, 12, 20];
const poBonusie = wyniki.map(punkty => punkty + 5);
const nagrody = poBonusie.filter(punkty => punkty >= 15);
nagrody.forEach((punkty, indeks) => {
console.log("Nagroda " + (indeks + 1) + ": " + punkty);
});
console.log("Oryginał: " + wyniki.join(", "));Nagroda 1: 17
Nagroda 2: 25
Oryginał: 5, 12, 20Jak program dochodzi do wyniku
- map wywołuje callback dla każdego elementu i zbiera jego wyniki do nowej tablicy: 10, 17, 25.
- filter zostawia elementy, dla których callback zwrócił true. Nie zamienia ich na wartości logiczne.
- forEach przekazuje element i jego indeks. Indeks zaczyna się od zera, więc numer nagrody zwiększamy o 1.
- Oryginał nie zmienił się: callbacki wykonują tu obliczenia na liczbach. Same map i filter nie gwarantują jednak, że callback nie zmodyfikuje obiektów.
Zanim przejdziesz dalej
Co stanie się po zamianie punkty => punkty + 5 na punkty => { punkty + 5; }?
Sprawdź swoje rozumowanie
Callback z blokiem nie zwraca wartości. map utworzy tablicę wartości undefined, a typ wyniku będzie void[]. Dodaj return lub usuń klamry.
Zmień kod i zobacz, co się stanie
Własna funkcja wykonuje callback
Callback nie musi działać później. Ta funkcja wywołuje go natychmiast w zwykłej pętli. Samo użycie strzałki nie sprawia, że kod jest asynchroniczny.
function powtorz(ile: number, akcja: (numer: number) => void): void {
for (let i = 1; i <= ile; i++) { akcja(i); }
}
powtorz(3, numer => console.log("Runda " + numer));Runda 1
Runda 2
Runda 3Funkcje strzałkowe nie mają własnego this: przejmują je z otoczenia. Wrócimy do tego przy klasach. Na razie ważniejsze jest odróżnienie funkcji od wyniku jej wywołania.
Gdy wynik zaskakuje
| Pomyłka | Co się dzieje i jak to poprawić |
|---|---|
| Przekazujesz podwoj(5) zamiast podwoj | Pierwszy zapis daje liczbę. Callbackiem ma być funkcja, którą odbiorca sam wywoła. |
| forEach zamiast map | forEach zwraca undefined. Do zbudowania nowej tablicy użyj map. |
| Próba break w callbacku forEach | break nie przerywa wywołującej pętli przez granicę funkcji. Wybierz for…of, jeśli potrzebujesz przerwania. |
Teraz Twoja kolej
Rozwiązanie jest jedną z możliwości. Zanim je odkryjesz, uruchom własną wersję dla podanych danych i przynajmniej jednego przypadku brzegowego.
Napisz strzałkę zamieniającą minuty na sekundy. Sprawdź 0 i 3.
Mała podpowiedź
Jedno wyrażenie nie potrzebuje klamer.
Przykładowe rozwiązanie z wyjaśnieniem
const sekundy = (minuty: number): number => minuty * 60;
console.log(sekundy(0), sekundy(3));0 180Typ wyniku zapisujemy dla czytelności, mimo że kompilator potrafi go ustalić.
Z tablicy [„ala”, „pixel”] utwórz nową tablicę wielkich liter. Wypisz wynik i oryginał.
Mała podpowiedź
map zbiera tekst zwrócony przez toUpperCase.
Przykładowe rozwiązanie z wyjaśnieniem
const nicki = ["ala", "pixel"];
const glosne = nicki.map(nick => nick.toUpperCase());
console.log(glosne.join(", "));
console.log(nicki.join(", "));ALA, PIXEL
ala, pixelTeksty są niemutowalne; wynik metody trzeba wykorzystać.
Wybierz wyniki co najmniej 50 z [49, 50, 80], potem dopisz „pkt” do każdego. Zachowaj kolejność.
Mała podpowiedź
Najpierw filter, potem map.
Przykładowe rozwiązanie z wyjaśnieniem
const zaproszeni = [49, 50, 80]
.filter(p => p >= 50)
.map(p => p + " pkt");
console.log(zaproszeni.join(" | "));50 pkt | 80 pktGranica 50 zostaje, ponieważ użyliśmy >=, a nie >.
Napisz oblicz(a, b, dzialanie). Przetestuj dodawanie i mnożenie dla 3 i 4 bez if i switch w oblicz.
Mała podpowiedź
Parametr działania przyjmuje dwie liczby i oddaje jedną.
Przykładowe rozwiązanie z wyjaśnieniem
function oblicz(a: number, b: number, dzialanie: (x: number, y: number) => number): number {
return dzialanie(a, b);
}
console.log(oblicz(3, 4, (x, y) => x + y));
console.log(oblicz(3, 4, (x, y) => x * y));7
12Funkcja oblicz nie zna zasad działania: dostaje je od wywołującego.
Co zabierasz do następnej lekcji
- Krótka strzałka zwraca wyrażenie; blok wymaga return.
- Callback to przekazana funkcja, nie wynik wywołania.
- map przekształca, filter wybiera, forEach wykonuje czynność.