Temat 07 · 2 × 45 minINF.03
Funkcje
Funkcja to nazwany fragment kodu, który możesz uruchomić wiele razy, z różnymi danymi, jednym poleceniem. Zamiast trzech kopii niemal identycznego kodu dla trzech przycisków piszesz jedną funkcję z parametrem. Na egzaminie praktycznym to właśnie funkcja jest podpięta do przycisku „Oblicz”, a od 2024 r. osobne kryterium ocenia, czy jej nazwa mówi, co robi. W części pisemnej pytania dotyczą liczby parametrów, tego, co zwraca return, i poprawnego wywołania.
Po co funkcje?
Jeden z arkuszy z czerwca 2024 każe trzem cytatom przełączać się po kliknięciu i dopuszcza „jedną funkcję parametrową lub trzy osobne”. Trzy osobne to trzy razy ten sam kod z inną liczbą. Jedna funkcja z parametrem robi to samo w pięciu linijkach – i gdy znajdziesz błąd, poprawiasz go w jednym miejscu.
// Tak wygląda kod bez funkcji – trzy niemal identyczne bloki
const cenaA = 4 * 10;
console.log("koszt paliwa: " + cenaA + " zł");
const cenaB = 3.5 * 10;
console.log("koszt paliwa: " + cenaB + " zł");
const cenaC = 0 * 10;
console.log("koszt paliwa: " + cenaC + " zł");// To samo z funkcją: logika w jednym miejscu, trzy wywołania
function wypiszKoszt(cenaLitra, litry) {
const koszt = cenaLitra * litry;
console.log("koszt paliwa: " + koszt + " zł");
}
wypiszKoszt(4, 10);
wypiszKoszt(3.5, 10);
wypiszKoszt(0, 10);Deklaracja i wywołanie
function nazwaFunkcji(parametr1, parametr2) { // deklaracja – nic jeszcze nie robi
// ciało: instrukcje do wykonania
return wynik; // opcjonalnie: co funkcja oddaje
}
nazwaFunkcji(argument1, argument2); // wywołanie – dopiero teraz kod się wykonujeSłowo function, nazwa, w nawiasach lista parametrów (nazwy zmiennych, które funkcja dostanie), w klamrach ciało. Sama deklaracja niczego nie uruchamia – kod wykona się dopiero przy wywołaniu: nazwa i nawiasy, w nich argumenty (konkretne wartości).
Co wypisze ten kod?
function powitaj() {
console.log("Cześć!");
}
powitaj();
powitaj();
console.log("Koniec");function powitaj(imie) {
console.log(`Cześć, ${imie}!`);
}
powitaj("Ola"); // argument "Ola" trafia do parametru imie
powitaj("Bartek");
powitaj(); // brak argumentu → imie ma wartość undefinedParametry i argumenty
Parametr to nazwa w deklaracji (imie), argument to wartość przy wywołaniu ("Ola"). Argumenty przypisują się do parametrów po kolei – nazwy się nie liczą, liczy się pozycja. Brakujące argumenty dają undefined, nadmiarowe są ignorowane.
function opiszZakup(produkt, cena, sztuk) {
console.log(`${sztuk} × ${produkt} po ${cena} zł`);
}
opiszZakup("zeszyt", 4.5, 3); // 3 × zeszyt po 4.5 zł
opiszZakup(3, "zeszyt", 4.5); // 4.5 × 3 po zeszyt zł – pozycje się nie zgadzają
opiszZakup("długopis", 2); // undefined × długopis po 2 zł – brak trzeciego argumentuParametr może mieć wartość domyślną, używaną, gdy argument nie został podany:
function cenaZVat(netto, stawka = 23) {
return netto * (1 + stawka / 100);
}
console.log(cenaZVat(100)); // 123 – użyta domyślna stawka
console.log(cenaZVat(100, 8)); // 108return – funkcja oddaje wynik
Funkcja, która tylko wypisuje w konsoli, jest mało użyteczna: wyniku nie da się dodać, porównać ani wstawić do akapitu. return zwraca wartość do miejsca wywołania – tam wyrażenie funkcja(…) „zamienia się” w tę wartość.
Jaką wartość będzie miała zmienna c?
function licz(a, b) {
return a * b;
}
var c = licz(3, 4) + 1;function polowaKwadratu(a) {
return a * a / 2;
}
const wynik = polowaKwadratu(6); // wynik = 18 – zapisujemy, co funkcja zwróciła
console.log(wynik);
console.log(polowaKwadratu(4) + polowaKwadratu(2)); // 8 + 2 = 10 – wyniki można dodawać
console.log(`Pole trójkąta: ${polowaKwadratu(10)}`); // i wstawiać do napisuTrzy fakty o return, o które pyta egzamin
1. return kończy funkcję. Kod po nim się nie wykona. Dlatego „wczesny return” jest wygodny do walidacji:
function opiszOcene(punkty) {
if (punkty < 0 || punkty > 100) {
return "Błędna liczba punktów"; // koniec – reszta się nie wykona
}
if (punkty >= 50) {
return "zdane";
}
return "niezdane"; // tu trafiamy tylko dla 0–49
}
console.log(opiszOcene(120), "|", opiszOcene(70), "|", opiszOcene(20));2. Funkcja bez return zwraca undefined. Wypisanie w konsoli to nie zwrócenie.
Co wypisze ten kod?
function dodaj(a, b) {
console.log(a + b);
}
var suma = dodaj(2, 3);
console.log(suma);function dodajWypisz(a, b) {
console.log("W funkcji:", a + b); // wypisuje, ale nie oddaje wyniku
}
function dodajZwroc(a, b) {
return a + b; // oddaje wynik, nic nie wypisuje
}
const w1 = dodajWypisz(2, 3);
const w2 = dodajZwroc(2, 3);
console.log("w1 =", w1, "| w2 =", w2); // w1 = undefined | w2 = 53. return zwraca jedną wartość. Funkcja nie może „zwrócić dwóch wartości” – w pytaniu o function fun1(a, b, c) { return a * b; } poprawna odpowiedź brzmi: trzy parametry, zwraca jedną liczbę (iloczyn a i b; c jest nieużywany). Gdy naprawdę potrzebujesz kilku wyników, zwracasz tablicę lub obiekt (lekcje Tablice i Obiekty).
Zasięg zmiennych
Zmienna zadeklarowana wewnątrz funkcji (let, const, także var) jest lokalna – istnieje tylko podczas wykonywania funkcji i znika po return. Parametry też są lokalne. Z zewnątrz nie ma do nich dostępu.
function obliczBrutto(netto) {
const vat = netto * 0.23; // zmienna lokalna
return netto + vat;
}
console.log(obliczBrutto(100)); // 123
console.log(vat); // ReferenceError: vat is not defined – nie istnieje poza funkcjąOdwrotnie działa to bez problemu: funkcja widzi zmienne zadeklarowane poza nią (globalne) i może je zmieniać. Tak przechowuje się stan między kliknięciami – np. numer aktualnego zdjęcia w galerii:
let numerZdjecia = 1; // stan poza funkcją – przeżywa kolejne wywołania
const ileZdjec = 3;
function nastepne() {
numerZdjecia++;
if (numerZdjecia > ileZdjec) { // zawijanie: po ostatnim wracamy do pierwszego
numerZdjecia = 1;
}
console.log("Pokazuję", numerZdjecia + ".jpg");
}
nastepne(); // 2.jpg
nastepne(); // 3.jpg
nastepne(); // 1.jpgGdyby let numerZdjecia = 1 stało wewnątrz nastepne(), każde kliknięcie zaczynałoby od 1 i galeria utknęłaby na 2.jpg – to realny błąd z zadań egzaminacyjnych (lekcja Stan aplikacji).
Funkcja jako wartość: wyrażenie funkcyjne i strzałka
Funkcję można zapisać w zmiennej jak każdą inną wartość. Dwie równoważne składnie:
// deklaracja
function podwoj(x) {
return x * 2;
}
// wyrażenie funkcyjne – funkcja bez nazwy przypisana do stałej
const potroj = function (x) {
return x * 3;
};
// funkcja strzałkowa (arrow function) – krótszy zapis tego samego
const poczworz = (x) => {
return x * 4;
};
// strzałka z jednym wyrażeniem: bez klamer i bez return – wynik wyrażenia jest zwracany
const popiec = (x) => x * 5;
console.log(podwoj(2), potroj(2), poczworz(2), popiec(2)); // 4 6 8 10Składnia strzałkowa przydaje się przy krótkich funkcjach i przy zdarzeniach: przycisk.addEventListener('click', () => { … }). Pusty nawias () oznacza brak parametrów. Więcej o różnicach (np. this) w lekcji Składnia ES6+.
funkcja czy funkcja()?
Nazwa bez nawiasów to sama funkcja (wartość, którą można przekazać dalej). Nazwa z nawiasami to jej wywołanie – i to, co zwróciła.
function policz() {
return 42;
}
console.log(policz); // [Function: policz] (w Chrome: ƒ policz() {…}) – sama funkcja, nie wynik
console.log(policz()); // 42 – wynik wywołaniaTa różnica wraca w lekcji Zdarzenia: addEventListener('click', policz) przekazuje funkcję, która wykona się po kliknięciu; addEventListener('click', policz()) wywołuje ją od razu i przekazuje liczbę 42. Natomiast w atrybucie HTML jest odwrotnie: onclick="policz()" – tam wpisujesz kod do wykonania, więc nawiasy są potrzebne.
Znaczące nazwy – kryterium egzaminacyjne
Od 2024 r. arkusze ze skryptem JS wymagają znaczącego nazewnictwa zmiennych i funkcji (w języku polskim lub angielskim), a w zasadach oceniania jest to osobny punkt (np. 5.8 w sesji styczeń 2025). Egzaminator sprawdza go w kodzie źródłowym – nawet gdy skrypt nie działa.
| Źle (traci punkt) | Dobrze | Dlaczego |
|---|---|---|
function f1() | function obliczKoszt() | nazwa funkcji to czasownik + co robi |
var a, b, x1 | let cenaLitra, litry, kosztPaliwa | nazwa mówi, co zmienna zawiera |
function funkcja() | function pokazSekcje(numer) | „funkcja” nic nie znaczy |
let zm = ... | let liczbaRat = ... | skróty tylko powszechne (i, max, vat) |
function zrob_cos() | function sprawdzHaslo() | konkret zamiast ogólnika |
Konwencje: camelCase (obliczKoszt, cenaZaKg), bez polskich znaków w nazwach (kosztCalkowity, nie kosztCałkowity), funkcje od czasownika (oblicz, pokaz, sprawdz, pobierz), zmienne logiczne od czy/jest (czyZaznaczony). Licznik pętli i jest akceptowany.
Składanie funkcji
Dobry program to małe funkcje, które się nawzajem wywołują. Każda robi jedną rzecz, więc łatwo ją przetestować osobno. Oto cennik paliwa z poprzedniej lekcji rozbity na części:
function cenaLitra(rodzajPaliwa) {
if (rodzajPaliwa === 1) return 4;
if (rodzajPaliwa === 2) return 3.5;
return 0;
}
function kosztPaliwa(rodzajPaliwa, litry) {
return cenaLitra(rodzajPaliwa) * litry; // jedna funkcja korzysta z drugiej
}
function komunikatKoszt(rodzajPaliwa, litry) {
return `koszt paliwa: ${kosztPaliwa(rodzajPaliwa, litry)} zł`;
}
console.log(cenaLitra(2)); // 3.5 – testujemy osobno
console.log(kosztPaliwa(2, 10)); // 35
console.log(komunikatKoszt(1, 10)); // koszt paliwa: 40 złZapowiedź: jedna funkcja, trzy przyciski
Tak wygląda „jedna funkcja parametrowa” z arkusza czerwiec 2024 – w dialekcie egzaminacyjnym, z atrybutem onclick. Każdy przycisk wywołuje tę samą funkcję z innym argumentem.
<button onclick="pokazCytat(1)">Cytat 1</button>
<button onclick="pokazCytat(2)">Cytat 2</button>
<button onclick="pokazCytat(3)">Cytat 3</button>
<p id="cytat">Kliknij przycisk.</p>function pokazCytat(numer) {
const akapit = document.getElementById('cytat');
if (numer === 1) {
akapit.textContent = 'Programowanie to sztuka mówienia komputerowi, czego chcesz.';
} else if (numer === 2) {
akapit.textContent = 'Najpierw rozwiąż problem, potem napisz kod.';
} else {
akapit.textContent = 'Kod czyta się częściej, niż pisze.';
}
}Na egzaminie
Ściąga
| Składnia | Co robi | Przykład |
|---|---|---|
function nazwa(p1, p2) { … } | deklaracja funkcji z parametrami | function obliczKoszt(cena, sztuk) { … } |
nazwa(a1, a2) | wywołanie z argumentami (po kolei) | obliczKoszt(4.5, 3) |
return wartosc; | zwraca wartość i kończy funkcję | return cena * sztuk; |
brak return | funkcja zwraca undefined | let w = wypisz(); → w === undefined |
const w = f(x); | zapis wyniku do zmiennej | const koszt = obliczKoszt(4.5, 3); |
function f(p = 10) { } | wartość domyślna parametru | cenaZVat(100) używa 23 |
| zasięg lokalny | zmienne z wnętrza funkcji nie istnieją poza nią | const vat wewnątrz → vat na zewnątrz: błąd |
| zmienna globalna | zadeklarowana poza funkcją, pamięta stan między wywołaniami | let indeks = 0; nad funkcją |
const f = function (x) { … }; | wyrażenie funkcyjne | |
const f = (x) => x * 2; | funkcja strzałkowa; jedno wyrażenie = automatyczny return | (a, b) => a + b |
f vs f() | funkcja jako wartość vs wywołanie i wynik | addEventListener('click', f) ale onclick="f()" |
| nazwy | camelCase, czasownik dla funkcji, bez a, x1, f1 | pokazSekcje, liczbaRat, czyZaznaczony |
Zadania
Pierwsze funkcje
Napisz i przetestuj (po dwa wywołania każdej) funkcje:
poleProstokata(a, b)– zwraca pole,polowaKwadratu(a)– zwracaa * a / 2(jak w pytaniu egzaminacyjnym),czyParzysta(n)– zwracatrue/false,wiekszaLiczba(a, b)– zwraca większy z argumentów bez użyciaMath.max.
Wyniki wypisuj poza funkcjami, przez console.log(nazwa(...)) – funkcje mają tylko zwracać.
Pokaż rozwiązanie
function poleProstokata(a, b) {
return a * b;
}
function polowaKwadratu(a) {
return a * a / 2;
}
function czyParzysta(n) {
return n % 2 === 0; // porównanie już jest wartością true/false – nie trzeba if
}
function wiekszaLiczba(a, b) {
if (a > b) {
return a;
}
return b; // tu trafiamy, gdy a <= b
}
console.log(poleProstokata(3, 4), poleProstokata(2.5, 2)); // 12 5
console.log(polowaKwadratu(4), polowaKwadratu(10)); // 8 50
console.log(czyParzysta(10), czyParzysta(7)); // true false
console.log(wiekszaLiczba(3, 9), wiekszaLiczba(9, 3)); // 9 9Refaktoryzacja kalkulatorów
Zamień dwa programy z poprzednich lekcji na funkcje zwracające gotowy komunikat:
liczbaPuszek(powierzchnia)– jedna puszka farby wystarcza na 4 m²; zwróć napisLiczba potrzebnych puszek: N, gdzie N jest zaokrąglone w górę do liczby całkowitej (arkusz styczeń 2023, INF.03-01-23.01). Testy: 20 → 5, 21 → 6, 0 → 0.przelicz(kwota, kurs)– zwróć napis100 EUR = 430.00 PLN(kwota, dwa miejsca po przecinku, przeztoFixed(2)); kurs domyślny 4.30, jeśli nie podano.
Dodatkowo napisz funkcję komunikatKoszt(etykieta, wartosc, jednostka), która buduje napis w formacie etykieta: wartosc jednostka (np. Koszt całkowity: 8000 zł) i użyj jej, żeby wypisać dwa różne komunikaty.
Pokaż rozwiązanie
function liczbaPuszek(powierzchnia) {
const puszki = Math.ceil(powierzchnia / 4); // zaokrąglenie w górę
return `Liczba potrzebnych puszek: ${puszki}`;
}
console.log(liczbaPuszek(20)); // 5
console.log(liczbaPuszek(21)); // 6 – 5,25 w górę
console.log(liczbaPuszek(0)); // 0
function przelicz(kwota, kurs = 4.30) {
const wPln = kwota * kurs;
return `${kwota} EUR = ${wPln.toFixed(2)} PLN`;
}
console.log(przelicz(100)); // domyślny kurs
console.log(przelicz(50, 4.55)); // podany kurs
function komunikatKoszt(etykieta, wartosc, jednostka) {
return `${etykieta}: ${wartosc} ${jednostka}`;
}
console.log(komunikatKoszt("Koszt całkowity", 8000, "zł"));
console.log(komunikatKoszt("Pole powierzchni pomieszczenia", 24, "m²"));Audyt nazw
Poniższy skrypt działa poprawnie, ale na egzaminie straciłby kryterium „znaczące nazewnictwo”. Przepisz go, nadając funkcji i wszystkim zmiennym nazwy opisujące ich rolę (po polsku lub angielsku, camelCase). Działanie ma pozostać identyczne – sprawdź, że dla tych samych danych wypisuje ten sam napis.
function f1(a, b, c) {
var x = 0;
if (a) x = x + 5000;
if (b) x = x + 3000;
var y = x / c;
return "Koszt całkowity: " + x + " zł. Płacisz " + c + " rat po " + y + " zł";
}
console.log(f1(true, true, 4));Pokaż rozwiązanie
function obliczRaty(wybranoReact, wybranoJavaScript, liczbaRat) {
let kosztCalkowity = 0;
if (wybranoReact) {
kosztCalkowity += 5000; // cena kursu React.js
}
if (wybranoJavaScript) {
kosztCalkowity += 3000; // cena kursu JavaScript
}
const rata = kosztCalkowity / liczbaRat;
return `Koszt całkowity: ${kosztCalkowity} zł. Płacisz ${liczbaRat} rat po ${rata} zł`;
}
console.log(obliczRaty(true, true, 4)); // Koszt całkowity: 8000 zł. Płacisz 4 rat po 2000 zł
console.log(obliczRaty(false, true, 3)); // 3000 zł, 3 raty po 1000 złCo się zmieniło: f1 → obliczRaty (czasownik + cel), a/b → wybranoReact/wybranoJavaScript (zmienne logiczne), c → liczbaRat, x → kosztCalkowity, y → rata, var → let/const, klamry przy każdym if. To logika zadania z arkusza styczeń 2025 (INF.03-01-25.01) – w module DOM dołożysz do niego odczyt checkboxów i listy miast.
Koszt montażu paneli
Zadanie według wzoru z sesji styczeń 2025 („Montaż paneli”). Na stronie koszty.html są dwa pola numeryczne (szerokość i długość pomieszczenia w metrach), trzy pola radio z rodzajem paneli (laminowane 12 zł/m², winylowe 14 zł/m², deska 18 zł/m²) i przycisk „Oblicz”. Po kliknięciu, w akapicie pod przyciskiem:
- gdy oba pola są wypełnione (wartość większa od zera):
Pole powierzchni pomieszczenia: 24, koszt montażu 288, - w przeciwnym razie:
Wprowadź poprawne dane.
Napisz funkcję komunikatMontazu(szerokosc, dlugosc, rodzaj), gdzie rodzaj to napis "laminowane", "winylowe" albo "deska", zwracającą odpowiedni napis. Rozbij logikę na pomocniczą funkcję cenaZaMetr(rodzaj). Przetestuj dla (4, 6, “laminowane”) → 288, (3, 5, “deska”) → 270, (0, 5, “winylowe”) → komunikat o błędzie.
Kryteria w stylu „Zasad oceniania” (0/1):
- 5.1 skrypt zawiera co najmniej jedną funkcję o znaczącej nazwie,
- 5.2 pole powierzchni to iloczyn szerokości i długości,
- 5.3 koszt zależy od wybranego rodzaju paneli (12/14/18 zł za m²),
- 5.4 przy brakujących danych wyświetlany jest dokładnie tekst
Wprowadź poprawne dane., - 5.5 komunikat wyniku ma dokładnie podaną postać (przecinek, małe litery, brak „zł”),
- 5.6 wynik poprawny dla dwóch różnych zestawów danych.
Pokaż rozwiązanie
function cenaZaMetr(rodzaj) {
if (rodzaj === "laminowane") return 12;
if (rodzaj === "winylowe") return 14;
if (rodzaj === "deska") return 18;
return 0; // nieznany rodzaj – bezpieczna wartość
}
function komunikatMontazu(szerokosc, dlugosc, rodzaj) {
// walidacja najpierw – wczesny return kończy funkcję
if (!(szerokosc > 0) || !(dlugosc > 0)) { // łapie też NaN i undefined z pustego pola
return "Wprowadź poprawne dane.";
}
const pole = szerokosc * dlugosc;
const koszt = pole * cenaZaMetr(rodzaj);
return `Pole powierzchni pomieszczenia: ${pole}, koszt montażu ${koszt}`;
}
console.log(komunikatMontazu(4, 6, "laminowane")); // 24, 288
console.log(komunikatMontazu(3, 5, "deska")); // 15, 270
console.log(komunikatMontazu(0, 5, "winylowe")); // Wprowadź poprawne dane.
console.log(komunikatMontazu(NaN, 5, "winylowe")); // puste pole po parseFloat("") daje NaN – też błądDlaczego !(szerokosc > 0) zamiast szerokosc <= 0? Puste pole po konwersji parseFloat to NaN (uwaga: Number("") daje 0, które > 0 też odrzuci), a każde porównanie z NaN daje false – NaN <= 0 nie wyłapałoby błędu, !(NaN > 0) tak.
Kalendarz z małych funkcji
Zbuduj trzy funkcje, z których każda korzysta z poprzedniej:
czyPrzestepny(rok)– z lekcji o warunkach,dniWMiesiacu(miesiac, rok)– 31 dla miesięcy 1, 3, 5, 7, 8, 10, 12; 30 dla 4, 6, 9, 11; luty 28 lub 29 zależnie odczyPrzestepny,dniWRoku(rok)– pętla od 1 do 12 sumującadniWMiesiacu(ma dać 365 lub 366).
Sprawdź: dniWMiesiacu(2, 2024) → 29, dniWMiesiacu(2, 2023) → 28, dniWRoku(2024) → 366, dniWRoku(2023) → 365.
Pokaż rozwiązanie
function czyPrzestepny(rok) {
return (rok % 4 === 0 && rok % 100 !== 0) || rok % 400 === 0;
}
function dniWMiesiacu(miesiac, rok) {
switch (miesiac) {
case 4:
case 6:
case 9:
case 11:
return 30; // return kończy – break niepotrzebny
case 2:
return czyPrzestepny(rok) ? 29 : 28;
default:
return 31;
}
}
function dniWRoku(rok) {
let suma = 0;
for (let miesiac = 1; miesiac <= 12; miesiac++) {
suma += dniWMiesiacu(miesiac, rok);
}
return suma;
}
console.log(dniWMiesiacu(2, 2024), dniWMiesiacu(2, 2023)); // 29 28
console.log(dniWRoku(2024), dniWRoku(2023)); // 366 365Test powtórkowy
Test powtórkowy
Format jak w części pisemnej INF.03. Kod bywa w dialekcie egzaminacyjnym (var, document.write).
Funkcja została wywołana jako fun1(3, 24, 'Mnożymy'). Co można o niej powiedzieć?
function fun1(a, b, c) {
return a * b;
}Które wywołanie poprawnie zapisze wynik funkcji licz_pitagoras(a, b) w zmiennej c?
Co wypisze ten kod?
function policz(a) {
var wynik = a * 2;
}
document.write(policz(5));Funkcja function pole(a) { return a * a / 2; } oblicza:
Co wypisze ten kod?
function zmien() {
var liczba = 100;
}
var liczba = 5;
zmien();
console.log(liczba);Który zapis w atrybucie HTML uruchomi funkcję oblicz po kliknięciu przycisku?
Które z poniższych zapisów są równoważne?
// Kod 1
function razy2(x) { return x * 2; }
// Kod 2
const razy2 = (x) => x * 2;Co wypisze ten kod?
function sprawdz(n) {
if (n > 10) {
return "duża";
}
return "mała";
console.log("koniec");
}
console.log(sprawdz(3));Które nazwy spełniają egzaminacyjne kryterium „znaczące nazewnictwo zmiennych i funkcji”?
Co wypisze ten kod?
function dodaj(a, b = 10) {
return a + b;
}
console.log(dodaj(5), dodaj(5, 1));