Lekcja 6: Funkcje
Funkcje to bloki kodu, które można zdefiniować raz i wywoływać wielokrotnie w różnych miejscach programu. Pozwalają na organizację kodu, jego reużywalność i tworzenie bardziej złożonych aplikacji.
Definiowanie funkcji
Istnieje kilka sposobów definiowania funkcji w JavaScript:
Deklaracja funkcji (Function Declaration)
Najbardziej klasyczny sposób. Funkcje zadeklarowane w ten sposób są poddawane hoistingowi, co oznacza, że można je wywołać przed ich definicją w kodzie.
function nazwaFunkcji(parametr1, parametr2) {
// Ciało funkcji - kod do wykonania
console.log("Parametr 1:", parametr1);
console.log("Parametr 2:", parametr2);
// Opcjonalnie: zwracanie wartości
return parametr1 + parametr2;
}
// Wywołanie funkcji
let wynik = nazwaFunkcji(5, 10);
console.log("Wynik funkcji:", wynik); // Wynik funkcji: 15
Wyrażenie funkcyjne (Function Expression)
Funkcja jest przypisywana do zmiennej. Takie funkcje nie są hoistowane - nie można ich wywołać przed definicją.
const mojaFunkcja = function(parametr) {
console.log("Wywołano wyrażenie funkcyjne z parametrem:", parametr);
return parametr * 2;
};
// Wywołanie funkcji
let rezultat = mojaFunkcja(7);
console.log("Rezultat:", rezultat); // Rezultat: 14
Wyrażenia funkcyjne mogą być anonimowe (jak powyżej) lub nazwane (co jest przydatne przy debugowaniu).
Funkcje strzałkowe (Arrow Functions - ES6)
Bardziej zwięzły sposób zapisu funkcji, wprowadzony w ES6. Mają kilka istotnych różnic w zachowaniu (np. dotyczących słowa kluczowego this
), które omówimy później.
// Najprostsza forma
const powitaj = () => {
console.log("Witaj!");
};
powitaj(); // Witaj!
// Z jednym parametrem (nawiasy opcjonalne)
const kwadrat = x => {
return x * x;
};
// Lub jeszcze krócej (niejawny return)
const kwadratKrotko = x => x * x;
console.log(kwadrat(4)); // 16
console.log(kwadratKrotko(5)); // 25
// Z wieloma parametrami
const suma = (a, b) => {
return a + b;
};
// Lub krócej
const sumaKrotko = (a, b) => a + b;
console.log(suma(3, 8)); // 11
console.log(sumaKrotko(10, 2)); // 12
Parametry i argumenty
- Parametry: Zmienne wymienione w definicji funkcji (np.
parametr1
,parametr2
wfunction nazwaFunkcji(parametr1, parametr2)
). - Argumenty: Rzeczywiste wartości przekazywane do funkcji podczas jej wywołania (np.
5
i10
wnazwaFunkcji(5, 10)
).
Parametry domyślne (ES6)
Można zdefiniować domyślne wartości dla parametrów, które zostaną użyte, jeśli argument nie zostanie przekazany.
function przywitaj(imie = "Gościu") {
console.log(`Witaj, ${imie}!`);
}
przywitaj("Anna"); // Witaj, Anna!
przywitaj(); // Witaj, Gościu!
Parametry resztowe (Rest Parameters - ES6)
Pozwalają na zebranie dowolnej liczby pozostałych argumentów w tablicę.
function sumujWszystko(...liczby) {
let suma = 0;
for (const liczba of liczby) {
suma += liczba;
}
return suma;
}
console.log(sumujWszystko(1, 2, 3)); // 6
console.log(sumujWszystko(10, 20, 30, 40)); // 100
console.log(sumujWszystko(5)); // 5
console.log(sumujWszystko()); // 0
Zwracanie wartości (`return`)
Instrukcja return
kończy wykonanie funkcji i opcjonalnie zwraca wartość do miejsca wywołania. Jeśli funkcja nie ma instrukcji return
lub ma return
bez wartości, domyślnie zwraca undefined
.
function czyPelnoletni(wiek) {
if (wiek >= 18) {
return true;
} else {
return false;
}
// Lub krócej: return wiek >= 18;
}
let status = czyPelnoletni(25);
console.log("Czy pełnoletni?", status); // Czy pełnoletni? true
function nicNieZwraca() {
console.log("Ta funkcja nic nie zwraca jawnie.");
}
let wynikPusty = nicNieZwraca();
console.log("Wynik pustej funkcji:", wynikPusty); // Wynik pustej funkcji: undefined
Zakres zmiennych (Scope)
Określa, gdzie w kodzie zmienne są dostępne.
- Zakres globalny: Zmienne zadeklarowane poza jakąkolwiek funkcją są dostępne wszędzie.
- Zakres lokalny (funkcyjny): Zmienne zadeklarowane wewnątrz funkcji (za pomocą
var
,let
,const
) są dostępne tylko w tej funkcji. - Zakres blokowy (ES6): Zmienne zadeklarowane za pomocą
let
iconst
wewnątrz bloku kodu (np. wif
,for
) są dostępne tylko w tym bloku.
let globalnaZmienna = "Jestem globalna";
function mojaFunkcja() {
let lokalnaZmienna = "Jestem lokalna";
console.log(globalnaZmienna); // Dostęp do zmiennej globalnej
console.log(lokalnaZmienna); // Dostęp do zmiennej lokalnej
if (true) {
let blokowaZmienna = "Jestem blokowa";
console.log(blokowaZmienna);
}
// console.log(blokowaZmienna); // Błąd: blokowaZmienna is not defined
}
mojaFunkcja();
// console.log(lokalnaZmienna); // Błąd: lokalnaZmienna is not defined
Zadanie praktyczne
Napisz funkcję o nazwie obliczPoleProstokata
, która przyjmuje dwa parametry (długości boków a
i b
) i zwraca pole tego prostokąta. Wywołaj funkcję z przykładowymi wartościami i wyświetl wynik w konsoli.
Pokaż rozwiązanie
// Deklaracja funkcji
function obliczPoleProstokata(a, b) {
if (typeof a !== 'number' || typeof b !== 'number' || a <= 0 || b <= 0) {
return "Nieprawidłowe wymiary"; // Obsługa błędnych danych
}
return a * b;
}
// Wywołanie funkcji
let bok1 = 7;
let bok2 = 4;
let pole = obliczPoleProstokata(bok1, bok2);
console.log(`Pole prostokąta o bokach ${bok1} i ${bok2} wynosi: ${pole}`); // Wynik: 28
// Test z błędnymi danymi
console.log(obliczPoleProstokata(5, -2)); // Wynik: Nieprawidłowe wymiary
console.log(obliczPoleProstokata(10, "abc")); // Wynik: Nieprawidłowe wymiary
Zadanie do samodzielnego wykonania
Napisz funkcję strzałkową o nazwie znajdzMax
, która przyjmuje dowolną liczbę argumentów (użyj parametrów resztowych) i zwraca największą z przekazanych liczb. Przetestuj funkcję, przekazując jej różne zestawy liczb.
FAQ - Funkcje
Jaka jest główna różnica między deklaracją funkcji a wyrażeniem funkcyjnym?
Główna różnica to hoisting. Deklaracje funkcji są "podnoszone" na górę swojego zakresu, więc można je wywołać przed ich definicją w kodzie. Wyrażenia funkcyjne nie są hoistowane i muszą być zdefiniowane przed pierwszym użyciem.
Kiedy używać funkcji strzałkowych?
Funkcje strzałkowe są świetne dla krótkich, anonimowych funkcji (np. jako callbacki). Ich zwięzła składnia jest bardzo wygodna. Mają też inne zachowanie this
, co jest kluczowe w metodach obiektów i obsłudze zdarzeń (omówimy to później).
Czy funkcja może wywoływać samą siebie?
Tak, nazywa się to rekurencją (lub rekursją). Funkcja rekurencyjna wywołuje samą siebie, aby rozwiązać mniejszą wersję tego samego problemu. Ważne jest, aby miała warunek bazowy (kończący), który zapobiega nieskończonemu wywoływaniu.
Co to jest funkcja zwrotna (callback)?
Funkcja zwrotna (callback) to funkcja przekazana jako argument do innej funkcji, która ma zostać wywołana później, zazwyczaj po zakończeniu jakiejś operacji (np. asynchronicznej). Są one powszechnie używane w JavaScript, np. w obsłudze zdarzeń czy operacjach asynchronicznych.
Czy kolejność parametrów ma znaczenie?
Tak, kolejność argumentów przekazywanych podczas wywołania funkcji musi odpowiadać kolejności parametrów w jej definicji. Jeśli przekażesz mniej argumentów niż parametrów, pozostałe parametry otrzymają wartość undefined
(chyba że mają wartości domyślne).
Co to jest IIFE (Immediately Invoked Function Expression)?
IIFE to wyrażenie funkcyjne, które jest definiowane i wywoływane natychmiast. Służy do tworzenia prywatnego zakresu dla zmiennych, aby uniknąć zanieczyszczania zakresu globalnego. Przykład: (function() { /* kod */ })();
.