Temat 14 · 3 × 45 minINF.03
Wzorzec egzaminacyjny „kalkulator”: kontrolki → obliczenie → akapit
Blisko połowa zadań z JavaScriptem w części praktycznej INF.03 to ten sam schemat: użytkownik wpisuje lub zaznacza dane, klika przycisk, a skrypt liczy coś i wypisuje wynik w akapicie pod przyciskiem. Ten schemat nazywamy kalkulatorem. Umiesz już wszystkie jego klocki – odczyt kontrolek (lekcja 13), konwersję (lekcja 3), warunki (lekcja 5), funkcje (lekcja 7) i zmianę treści (lekcja 11). W tej lekcji złożysz je w jedną, powtarzalną procedurę, która zdobywa wszystkie kryteria zasad oceniania – i przećwiczysz ją na trzech zadaniach na czas.
Jak wygląda zadanie „kalkulator”
Arkusz opisuje stronę (np. cena.html) z kilkoma kontrolkami i przyciskiem, a na końcu opisu skryptu podaje format wyniku. Oto oryginalne zadanie w stylu CKE, na którym będziemy pracować w całej lekcji:
Zasady oceniania dla takiego zadania (rezultat 5 „Skrypt”) wyglądałyby tak – każde kryterium za 0 lub 1:
| Nr | Kryterium (styl „Zasad oceniania”) | Gdzie sprawdzane |
|---|---|---|
| 5.1 | Skrypt napisany w JavaScript, zawiera co najmniej jedną poprawną składniowo instrukcję; funkcja wywoływana przyciskiem „Oblicz” | kod źródłowy |
| 5.2 | Skrypt pobiera dane z co najmniej jednej kontrolki, np. document.getElementById | kod źródłowy |
| 5.3 | Koszt liczony jako cena za godzinę × liczba godzin, cena zależna od zaznaczonego rodzaju roweru | kod + wynik |
| 5.4 | Dopłata 5 zł dodawana tylko przy zaznaczonym polu „Kask” | kod + wynik |
| 5.5 | Wynik w akapicie pod przyciskiem w formacie Koszt wypożyczenia: <koszt> zł – sprawdzany dla dwóch różnych zestawów danych | przeglądarka |
| 5.6 | Co najmniej jedna zmienna lub funkcja o znaczącej nazwie (PL/EN) | kod źródłowy |
Krok 0: czytaj kryterium po kryterium
Zanim napiszesz linię kodu, rozbij polecenie na czynności. Każde zdanie z arkusza to zwykle jedno kryterium, a każde kryterium to jedna–trzy linie kodu. Zrób sobie taką tabelę w głowie (albo na kartce brudnopisu, którą masz na egzaminie):
| Fragment polecenia | Co muszę zrobić | Linia kodu |
|---|---|---|
| „uruchamiany po kliknięciu przycisku” | funkcja + podpięcie do przycisku | function obliczKoszt() {…} + onclick="obliczKoszt()" |
| „pobiera liczbę godzin” | odczyt + konwersja | const godziny = parseFloat(document.getElementById('godziny').value); |
| „wybrany rodzaj roweru” | zaznaczony radio | document.querySelector('input[name="rower"]:checked').value |
| „stan pola Kask” | checkbox | document.getElementById('kask').checked |
| „cena za godzinę razy liczba godzin” | mnożenie | let koszt = cenaZaGodzine * godziny; |
| „plus 5 zł, jeśli zaznaczono” | if | if (kask) koszt += 5; |
| „wypisuje w pustym akapicie: Koszt wypożyczenia: … zł” | napis + innerHTML | wynik.innerHTML = 'Koszt wypożyczenia: ' + koszt + ' zł'; |
| „znaczące nazewnictwo” | nazwy | obliczKoszt, cenaZaGodzine, nie f1, x |
Z tej tabeli wynika kolejność pisania kodu. Przejdziemy ją krok po kroku.
Krok 1: HTML – przycisk i pusty akapit pod nim
Arkusz mówi „w pustym akapicie pod przyciskiem”. To znaczy dosłownie: <p> bez treści, z id, umieszczony za przyciskiem. Nie <div>, nie <span>, nie alert – egzaminator sprawdza miejsce wyświetlenia (w styczniu 2024 było to osobne kryterium: „komunikat wyświetlony w bloku głównym w akapicie”).
<label for="godziny">Liczba godzin:</label>
<input type="number" id="godziny" min="1" value="1">
<br>
<input type="radio" name="rower" value="8" id="miejski" checked>
<label for="miejski">Rower miejski – 8 zł/h</label>
<input type="radio" name="rower" value="20" id="elektryczny">
<label for="elektryczny">Rower elektryczny – 20 zł/h</label>
<br>
<input type="checkbox" id="kask">
<label for="kask">Kask (+5 zł)</label>
<br>
<button type="button" onclick="obliczKoszt()">Oblicz</button>
<p id="wynik"></p>Trzy zasady:
- Każda kontrolka ma
id(radio – wspólnenamei własnevalue). Bez tego nie ma czego czytać. - Przycisk ma
type="button"albo nie jest w<form>– inaczej kliknięcie przeładuje stronę i wynik zniknie po ułamku sekundy. - Akapit jest pusty i ma
id–<p id="wynik"></p>. Możesz go nazwać inaczej (komunikat,koszt), byle konsekwentnie w JS.
Krok 2: funkcja i jej uruchomienie – dwa style
Arkusze CKE „myślą” w dialekcie egzaminacyjnym: atrybut onclick, var, getElementById, innerHTML. Tabela pomocnicza dołączona do każdego arkusza wymienia właśnie onclick i innerHTML. Ty możesz pisać tak samo albo nowocześnie. Porównaj dwa równoważne rozwiązania tego samego zadania:
<label for="godziny">Liczba godzin:</label>
<input type="number" id="godziny" min="1" value="1"><br>
<input type="radio" name="rower" value="8" id="miejski" checked> <label for="miejski">Rower miejski – 8 zł/h</label>
<input type="radio" name="rower" value="20" id="elektryczny"> <label for="elektryczny">Rower elektryczny – 20 zł/h</label><br>
<input type="checkbox" id="kask"> <label for="kask">Kask (+5 zł)</label><br>
<button type="button" onclick="obliczKoszt()">Oblicz</button>
<p id="wynik"></p>function obliczKoszt() {
var godziny = parseFloat(document.getElementById('godziny').value);
var cenaZaGodzine;
if (document.getElementById('elektryczny').checked) {
cenaZaGodzine = 20;
} else {
cenaZaGodzine = 8;
}
var koszt = cenaZaGodzine * godziny;
if (document.getElementById('kask').checked) {
koszt = koszt + 5;
}
document.getElementById('wynik').innerHTML = 'Koszt wypożyczenia: ' + koszt + ' zł';
}Ten sam efekt w stylu nowoczesnym – przycisk ma id, a funkcję podpina skrypt umieszczony pod przyciskiem:
<label for="godziny">Liczba godzin:</label>
<input type="number" id="godziny" min="1" value="1"><br>
<input type="radio" name="rower" value="8" id="miejski" checked> <label for="miejski">Rower miejski – 8 zł/h</label>
<input type="radio" name="rower" value="20" id="elektryczny"> <label for="elektryczny">Rower elektryczny – 20 zł/h</label><br>
<input type="checkbox" id="kask"> <label for="kask">Kask (+5 zł)</label><br>
<button type="button" id="oblicz">Oblicz</button>
<p id="wynik"></p>const przyciskOblicz = document.querySelector('#oblicz');
const akapitWyniku = document.querySelector('#wynik');
function obliczKoszt() {
const godziny = parseFloat(document.querySelector('#godziny').value);
const cenaZaGodzine = parseFloat(document.querySelector('input[name="rower"]:checked').value);
const kask = document.querySelector('#kask').checked;
let koszt = cenaZaGodzine * godziny;
if (kask) koszt += 5;
akapitWyniku.textContent = `Koszt wypożyczenia: ${koszt} zł`;
}
przyciskOblicz.addEventListener('click', obliczKoszt);Kiedy który styl jest w porządku na egzaminie?
| Styl egzaminacyjny | Styl nowoczesny | |
|---|---|---|
| Podpięcie | onclick="obliczKoszt()" w HTML – widoczne od razu, nie zależy od miejsca <script> | addEventListener('click', obliczKoszt) – skrypt musi być po przycisku (koniec <body>) albo z defer |
| Odczyt | getElementById('x') | querySelector('#x') – to samo; querySelector dodatkowo obsługuje :checked |
| Wynik | innerHTML – akceptuje <br>, gdy wynik ma kilka linii | textContent – bezpieczniejszy, ale <br> wypisze dosłownie |
| Zmienne | var | const/let |
| Ryzyko | literówka w nazwie funkcji w atrybucie widoczna dopiero po kliknięciu | funkcja wywołana zamiast przekazana: addEventListener('click', obliczKoszt()) |
| Ocena | pełne punkty | pełne punkty – przeglądarka na stanowisku jest aktualna, a arkusz nie określa wersji języka |
Oba podejścia są poprawne. Jeśli masz choć cień wątpliwości, pisz styl egzaminacyjny – jest odporny na kolejność ładowania i wygląda jak przykłady CKE. Jeśli piszesz nowocześnie, pamiętaj o jednym: <script> na końcu <body>.
Krok 3: pobranie i konwersja
Kontrolki zwracają napisy. Zanim policzysz, zamień na liczby – inaczej "5" + 5 da "55", a mnożenie przypadkiem zadziała, więc błąd zauważysz dopiero przy dodawaniu dopłaty.
Użytkownik wpisał 3 godziny i zaznaczył kask. Co wypisze ten (błędny) skrypt?
var godziny = document.getElementById('godziny').value;
var koszt = 8 * godziny;
koszt = koszt + 5;
document.getElementById('wynik').innerHTML = 'Koszt: ' + koszt + ' zł';const godziny = parseFloat(document.getElementById('godziny').value); // "3" → 3
const liczbaRat = parseInt(document.getElementById('raty').value); // "12" → 12
const kask = document.getElementById('kask').checked; // true / false (bez konwersji)
const miasto = document.getElementById('miasto').value; // napis – zostaje napisemPrzypomnienie z lekcji 13: parseFloat do kwot i wymiarów, parseInt do liczby sztuk i rat, Number gdy chcesz, by puste pole dało 0, valueAsNumber gdy wolisz pominąć value. Checkbox i radio czytasz przez checked – to już wartość logiczna.
Krok 4: obliczenie
Obliczenie to zwykle 2–4 linie: mnożenie, suma zaznaczonych, warunek na dopłatę lub cenę zależną od wyboru, czasem zaokrąglenie. Zasady:
- Każdy checkbox osobno – kryterium „testując zaznaczenie każdego pola wyboru” (styczeń 2025). Cztery checkboxy = cztery
if. - Cena zależna od wyboru –
if/else if/elsepo wartości radio lub pola numerycznego, albo bezpośrednioparseFloat(radio.value), jeśli wvaluewpisałeś cenę. - „Zaokrąglona w górę do liczby całkowitej” =
Math.ceil. „W dół” =Math.floor. „Do najbliższej” =Math.round. W styczniu 2023 (INF.03-01-23.01) brak zaokrąglenia w górę kosztował osobne kryterium. - Dzielenie przez liczbę rat – uważaj na
0: dzielenie przez zero dajeInfinity. Zabezpieczmin="1"w HTML, a najlepiej jeszczeif. - Grosze –
toFixed(2)daje napis z dwiema cyframi po przecinku ("12.50"). Użyj, gdy arkusz pokazuje kwotę z groszami; w innym wypadku zostaw liczbę.
// cena zależna od numeru (jak w arkuszu „stacja paliw” z czerwca 2022)
function cenaPaliwa(rodzaj) {
if (rodzaj === 1) return 4;
else if (rodzaj === 2) return 3.5;
else return 0;
}
console.log(cenaPaliwa(2) * 30); // 105
// zaokrąglenie w górę (jak w arkuszu „malarz” ze stycznia 2023)
const powierzchnia = 37;
console.log(Math.ceil(powierzchnia / 4)); // 10 – nie 9.25 i nie 9
// rata z groszami
const koszt = 8000;
const raty = 12;
console.log((koszt / raty).toFixed(2)); // "666.67" – uwaga: to napisKrok 5: dokładny format napisu
To tu ucieka najwięcej punktów. Kryterium brzmi: „pod przyciskiem wyświetla się napis Liczba potrzebnych puszek: <wynik>”. Egzaminator porównuje z arkuszem – drobne literówki i wielkość liter są tolerowane, ale brakujące słowo, dwukropek, jednostka albo zła kolejność mogą kosztować punkt. Przy formacie „Kurs odbędzie się w X. Koszt całkowity: Y zł. Płacisz N rat po Z zł” sprawdzane są trzy osobne kryteria: miasto, koszt, raty.
| Arkusz żąda | Student wypisał | Problem |
|---|---|---|
Koszt wypożyczenia: 29 zł | 29 | brak etykiety i jednostki |
Koszt wypożyczenia: 29 zł | Koszt wypożyczenia 29zł | brak dwukropka i spacji – egzaminator może uznać to za drobną literówkę, ale nie musi; po co ryzykować |
Koszt wypożyczenia: 29 zł | Koszt wypożyczenia: 29 zł w alert() | złe miejsce – kryterium „w akapicie” przepada |
Koszt wypożyczenia: 29 zł | Koszt wypożyczenia: 29.000000001 zł | błąd zmiennoprzecinkowy – toFixed(2) lub Math.round |
Koszt wypożyczenia: 29 zł | Koszt wypożyczenia: NaN zł | puste pole lub brak konwersji – walidacja |
Dwa równoważne zapisy – wybierz ten, w którym robisz mniej literówek:
const koszt = 29;
const miasto = 'Gdańsk';
const raty = 3;
// konkatenacja (dialekt egzaminacyjny) – pilnuj spacji w cudzysłowach
console.log('Koszt wypożyczenia: ' + koszt + ' zł');
// template string – tekst wygląda jak w arkuszu, wartości w ${}
console.log(`Kurs odbędzie się w ${miasto}. Koszt całkowity: ${koszt} zł. Płacisz ${raty} rat po ${(koszt / raty).toFixed(2)} zł`);Jeśli wynik ma kilka linii („w pierwszej linii imię i nazwisko, poniżej treść zgłoszenia” – styczeń 2024), użyj innerHTML z <br>:
wynik.innerHTML = imie.toUpperCase() + ' ' + nazwisko.toUpperCase() + '<br>' +
'Treść Twojej sprawy:<br>' + tresc;textContent wypisałby <br> jako zwykły tekst. Z kolei innerHTML traktuje treść jak HTML – jeśli użytkownik wpisze <b>, zostanie to zinterpretowane. Na egzaminie to bez znaczenia, w prawdziwej aplikacji wybieraj textContent, gdy nie potrzebujesz znaczników.
Arkusz wymaga napisu Liczba puszek: <wynik> w akapicie pod przyciskiem. Które kryterium NIE zostanie spełnione przez ten kod?
function policz() {
var powierzchnia = parseFloat(document.getElementById('pow').value);
var puszki = Math.ceil(powierzchnia / 4);
alert('Liczba puszek: ' + puszki);
}Krok 6: walidacja – „Wprowadź poprawne dane.”
Niektóre arkusze (styczeń 2025, INF.03-02-25.01) wymagają: „gdy oba pola są wypełnione – wynik; w przeciwnym razie komunikat Wprowadź poprawne dane.”. Inne zwalniają z walidacji wprost („dla uproszczenia wszelką walidację należy pominąć”). Jeśli arkusz nic nie mówi – prosta walidacja nie zaszkodzi, ale nie trać na nią czasu.
Wzorzec: sprawdź na początku funkcji, wypisz komunikat i zakończ return, żeby nie liczyć dalej:
<label>Szerokość [m]: <input type="number" id="szerokosc"></label><br>
<label>Długość [m]: <input type="number" id="dlugosc"></label><br>
<button type="button" onclick="obliczPole()">Oblicz</button>
<p id="wynik"></p>function obliczPole() {
const szerokosc = parseFloat(document.getElementById('szerokosc').value);
const dlugosc = parseFloat(document.getElementById('dlugosc').value);
const wynik = document.getElementById('wynik');
if (isNaN(szerokosc) || isNaN(dlugosc)) { // puste pole → parseFloat daje NaN
wynik.innerHTML = 'Wprowadź poprawne dane.';
return; // koniec – nie liczymy dalej
}
const pole = szerokosc * dlugosc;
wynik.innerHTML = 'Pole powierzchni pomieszczenia: ' + pole + ' m², koszt montażu ' + pole * 12 + ' zł';
}isNaN(x) zwraca true, gdy x nie jest liczbą – łapie puste pole i błędny tekst. Jeśli chcesz dodatkowo odrzucić wartości ujemne lub zero: if (isNaN(szerokosc) || szerokosc <= 0 || …). Pełną walidację (HTML5 required, min, pattern) poznasz w lekcji 18.
Krok 7: test na dwóch zestawach danych
Zasady oceniania mówią wprost: „sprawdzane dla dwóch różnych miast”, „dla dwóch różnych wartości rat”. Egzaminator kliknie co najmniej dwa razy z innymi danymi. Ty zrób to pierwszy – i policz oczekiwany wynik na kartce, zanim klikniesz:
| Zestaw | Godziny | Rower | Kask | Oczekiwane | Skrypt wypisał |
|---|---|---|---|---|---|
| A | 3 | miejski (8) | nie | 24 | Koszt wypożyczenia: 24 zł |
| B | 2 | elektryczny (20) | tak | 45 | Koszt wypożyczenia: 45 zł |
Zestawy dobieraj tak, by każda gałąź kodu zadziałała: inny radio, zaznaczony i niezaznaczony checkbox, inna pozycja listy. Jeśli zadanie ma walidację – trzeci test z pustym polem. Jeżeli wynik jest zły, nie zgaduj: otwórz konsolę (F12), dodaj console.log(godziny, cenaZaGodzine) i zobacz, która wartość jest nie taka.
Gdy skrypt nie działa – co sprawdzi egzaminator
Najgorszy scenariusz: błąd składni (brakujący nawias, literówka w getElementById) i skrypt w ogóle nie startuje. Zasady oceniania mają na to regułę: „jeśli skrypt się nie uruchamia, kryteria X sprawdza się w kodzie źródłowym” – w styczniu 2023 były to kryteria 5.1–5.4 (język, pobranie, dzielenie, zaokrąglenie), w styczniu 2025 – 5.1–5.4 i 5.8 (nazewnictwo). Kryteria wyjściowe (napis w akapicie, poprawny wynik dla dwóch zestawów) przepadają.
Wniosek: nawet niedziałający skrypt może zdobyć 4–5 z 8 kryteriów, jeśli w kodzie widać właściwe konstrukcje. Zadbaj, by w pliku było:
<script>z funkcją (kryterium języka),document.getElementById(...).valuelub.checked(pobranie danych),- linia z działaniem z arkusza:
/ 4,Math.ceil(...),* liczbaGodzin(obliczenia), - znaczące nazwy.
A żeby skrypt jednak działał – lista najczęstszych przyczyn „nic się nie dzieje”:
| Objaw | Przyczyna | Jak znaleźć |
|---|---|---|
kliknięcie nic nie robi, konsola: obliczKoszt is not defined | literówka w nazwie funkcji w onclick lub funkcja w innym bloku, który ma błąd składni | konsola F12 pokazuje też SyntaxError z numerem linii |
Cannot read properties of null (reading 'value') | id w HTML inne niż w getElementById (np. godziny vs godzina) albo <script> w <head> bez defer przy addEventListener | sprawdź id, przenieś <script> na koniec <body> |
| wynik znika po ułamku sekundy | przycisk w <form> wysyła formularz | type="button" lub usuń <form> |
NaN zł | brak konwersji przy pustym polu, literówka w value, parseFloat na checkboxie | console.log każdej zmiennej |
Koszt: 85 zł zamiast 13 zł | sklejanie napisów zamiast dodawania | parseFloat przy odczycie |
Infinity | dzielenie przez 0 rat | min="1" + walidacja |
Nazewnictwo – osobne kryterium od 2024
Od stycznia 2024 każdy arkusz zawiera zdanie „należy stosować znaczące nazewnictwo zmiennych i funkcji w języku polskim lub angielskim”, a zasady oceniania mają osobny punkt: „skrypt używa co najmniej jednej zmiennej lub funkcji, nazwy odzwierciedlają cel”. To najtańszy punkt na egzaminie – pod warunkiem, że piszesz cenaZaGodzine, a nie c.
| Źle (punkt stracony) | Dobrze (PL) | Dobrze (EN) |
|---|---|---|
function f1() | function obliczKoszt() | function calculateCost() |
var a, b, x1 | let godziny, cenaZaGodzine, koszt | let hours, pricePerHour, cost |
var zm = ... | const liczbaRat = ... | const installments = ... |
function funkcja() | function pokazWynik() | function showResult() |
Nazwy bez polskich znaków (dlugosc, nie długość) – polskie litery w identyfikatorach są technicznie dozwolone, ale proszą się o literówkę. Styl camelCase (cenaZaGodzine) lub z podkreśleniem (cena_za_godzine) – oba akceptowane, byle konsekwentnie.
Pełny przykład: od polecenia do rozwiązania
Zbierzmy wszystko w jedno rozwiązanie zadania przewodniego – z komentarzami, który fragment zdobywa które kryterium. Ten plik możesz traktować jako szablon, który na egzaminie przerabiasz pod konkretne polecenie.
<h2>Cennik wypożyczalni</h2>
<label for="godziny">Liczba godzin:</label>
<input type="number" id="godziny" min="1" value="1"><br>
<input type="radio" name="rower" value="8" id="miejski" checked>
<label for="miejski">Rower miejski – 8 zł/h</label>
<input type="radio" name="rower" value="20" id="elektryczny">
<label for="elektryczny">Rower elektryczny – 20 zł/h</label><br>
<input type="checkbox" id="kask"> <label for="kask">Kask (+5 zł)</label><br>
<button type="button" onclick="obliczKoszt()">Oblicz</button>
<p id="wynik"></p> <!-- 5.5: pusty akapit POD przyciskiem -->// 5.1: JavaScript, funkcja wywoływana przyciskiem (onclick="obliczKoszt()")
// 5.6: znaczące nazwy – obliczKoszt, liczbaGodzin, cenaZaGodzine, koszt
function obliczKoszt() {
// 5.2: pobranie danych z kontrolek + konwersja
const liczbaGodzin = parseFloat(document.getElementById('godziny').value);
const wybranyRower = document.querySelector('input[name="rower"]:checked');
const cenaZaGodzine = parseFloat(wybranyRower.value);
const zKaskiem = document.getElementById('kask').checked;
// walidacja (arkusz jej nie wymaga, ale chroni przed NaN)
if (isNaN(liczbaGodzin) || liczbaGodzin <= 0) {
document.getElementById('wynik').innerHTML = 'Wprowadź poprawne dane.';
return;
}
// 5.3: cena za godzinę × liczba godzin
let koszt = cenaZaGodzine * liczbaGodzin;
// 5.4: dopłata tylko przy zaznaczonym kasku
if (zKaskiem) {
koszt += 5;
}
// 5.5: dokładny format napisu w akapicie pod przyciskiem
document.getElementById('wynik').innerHTML = 'Koszt wypożyczenia: ' + koszt + ' zł';
}Testy: (3 h, miejski, bez kasku) → Koszt wypożyczenia: 24 zł; (2 h, elektryczny, kask) → Koszt wypożyczenia: 45 zł; (puste pole) → Wprowadź poprawne dane.
W którym miejscu kod poniżej ma błąd, przez który skrypt wyświetli Koszt: NaN zł dla każdego zestawu danych?
function obliczKoszt() {
var godziny = parseFloat(document.getElementById('godziny').value);
var cena = parseFloat(document.getElementById('kask').checked);
var koszt = godziny * 8 + cena;
document.getElementById('wynik').innerHTML = 'Koszt: ' + koszt + ' zł';
}Na egzaminie
Ściąga
| Krok | Składnia | Przykład |
|---|---|---|
| Przycisk + akapit | <button type="button" onclick="f()"> + <p id="wynik"></p> | akapit pod przyciskiem, pusty |
| Funkcja (egz.) | function obliczKoszt() { … } + onclick="obliczKoszt()" | nawiasy w atrybucie! |
| Funkcja (nowocz.) | btn.addEventListener('click', obliczKoszt) | bez nawiasów; <script> na końcu body |
| Odczyt liczby | parseFloat(document.getElementById('x').value) | parseInt dla sztuk/rat |
| Odczyt checkboxa | document.getElementById('x').checked | true/false, bez konwersji |
| Odczyt radio | document.querySelector('input[name="g"]:checked').value | jedno checked w HTML |
| Odczyt listy | document.getElementById('lista').value | tekst opcji, gdy brak value |
| Każdy checkbox | if (a.checked) suma += 60; if (b.checked) suma += 150; | osobne if |
| Cena wg wyboru | if (rodzaj === 1) cena = 4; else if (rodzaj === 2) cena = 3.5; else cena = 0; | lub parseFloat(radio.value) |
| W górę / w dół | Math.ceil(x) / Math.floor(x) / Math.round(x) | Math.ceil(37 / 4) → 10 |
| Grosze | kwota.toFixed(2) | zwraca napis "12.50" |
| Walidacja | if (isNaN(a) || isNaN(b)) { wynik.innerHTML = 'Wprowadź poprawne dane.'; return; } | na początku funkcji |
| Napis | 'Koszt: ' + koszt + ' zł' lub `Koszt: ${koszt} zł` | przepisz format z arkusza |
| Wynik | document.getElementById('wynik').innerHTML = napis; | <br> dla kilku linii |
| Debug | F12 → konsola; console.log(zmienna) | po każdej zmianie |
Zadania
Zadania 2–4 rób na czas: 20 minut każde, bez podglądania rozwiązania. Po skończeniu oceń się według listy kryteriów – uczciwie, 0 albo 1.
Przelicznik walut – rozgrzewka
Pole liczbowe „Kwota w PLN”, lista rozwijana z walutami: EUR (kurs 4,30), USD (3,95), GBP (5,05) – kurs wpisz w atrybucie value opcji, nazwę jako tekst. Przycisk Przelicz. Pod przyciskiem: <kwota> PLN = <wynik> <waluta>, wynik z dwoma miejscami po przecinku, np. 100 PLN = 23.26 EUR.
Pokaż rozwiązanie
<label>Kwota w PLN: <input type="number" id="kwota" value="100" min="0"></label>
<select id="waluta">
<option value="4.30">EUR</option>
<option value="3.95">USD</option>
<option value="5.05">GBP</option>
</select>
<button type="button" onclick="przelicz()">Przelicz</button>
<p id="wynik"></p>function przelicz() {
const kwotaPln = parseFloat(document.getElementById('kwota').value);
const lista = document.getElementById('waluta');
const kurs = parseFloat(lista.value); // value opcji = kurs
const nazwaWaluty = lista.options[lista.selectedIndex].text; // widoczny tekst = nazwa
const wynik = (kwotaPln / kurs).toFixed(2);
document.getElementById('wynik').innerHTML = kwotaPln + ' PLN = ' + wynik + ' ' + nazwaWaluty;
}Szkoła jazdy – raty (20 min)
Strona raty.html zawiera: dwa pola wyboru „Kurs kategorii B – 3200 zł” i „Jazdy doszkalające – 600 zł”, pole numeryczne „Liczba rat” (wartości od 1 do 12, domyślnie 1), listę rozwijaną „Oddział” z pozycjami Poznań, Wrocław, Łódź, przycisk „Oblicz” i pusty akapit pod przyciskiem.
Skrypt w JavaScript, uruchamiany przyciskiem, sumuje ceny zaznaczonych szkoleń, dzieli sumę przez liczbę rat i wypisuje w akapicie: Szkolenie w oddziale <oddział>. Koszt całkowity: <koszt> zł. Płacisz <liczba> rat po <rata> zł. Stosuj znaczące nazwy zmiennych i funkcji.
Kryteria samooceny (0/1):
- Skrypt w JavaScript, co najmniej jedna poprawna instrukcja; funkcja wywoływana przyciskiem.
- Pobiera dane z co najmniej jednej kontrolki.
- Liczy koszt zaznaczonych szkoleń, testując zaznaczenie każdego z dwóch pól wyboru.
- Pobiera liczbę rat i dzieli przez nią koszt.
- Wynik zawiera nazwę oddziału z listy – poprawnie dla dwóch różnych oddziałów.
- Wynik zawiera koszt całkowity.
- Wynik zawiera liczbę rat i wysokość raty – poprawnie dla dwóch różnych liczb rat.
- Znaczące nazwy zmiennych i funkcji.
Testy: (oba kursy, 4 raty, Wrocław) → Szkolenie w oddziale Wrocław. Koszt całkowity: 3800 zł. Płacisz 4 rat po 950 zł; (tylko kat. B, 1 rata, Łódź) → koszt 3200, rata 3200.
Pokaż rozwiązanie
<input type="checkbox" id="kursB"> <label for="kursB">Kurs kategorii B – 3200 zł</label><br>
<input type="checkbox" id="doszkalajace"> <label for="doszkalajace">Jazdy doszkalające – 600 zł</label><br>
<label>Liczba rat: <input type="number" id="raty" min="1" max="12" value="1"></label><br>
<label>Oddział:
<select id="oddzial">
<option>Poznań</option>
<option>Wrocław</option>
<option>Łódź</option>
</select>
</label><br>
<button type="button" onclick="obliczRaty()">Oblicz</button>
<p id="wynik"></p>function obliczRaty() {
// kryterium 3: każde pole wyboru osobno
let kosztCalkowity = 0;
if (document.getElementById('kursB').checked) kosztCalkowity += 3200;
if (document.getElementById('doszkalajace').checked) kosztCalkowity += 600;
// kryterium 4: liczba rat i dzielenie
const liczbaRat = parseInt(document.getElementById('raty').value);
const rata = kosztCalkowity / liczbaRat;
// kryterium 5: oddział z listy (tekst opcji)
const oddzial = document.getElementById('oddzial').value;
// kryteria 5–7: dokładny format
document.getElementById('wynik').innerHTML =
'Szkolenie w oddziale ' + oddzial + '. Koszt całkowity: ' + kosztCalkowity +
' zł. Płacisz ' + liczbaRat + ' rat po ' + rata + ' zł';
}Jeśli rata wychodzi z długim ułamkiem (np. 3800 / 3), możesz użyć rata.toFixed(2) – jeśli arkusz nie precyzuje zaokrąglenia, oba warianty powinny być w porządku.
Ogrodzenie – z walidacją (20 min)
Strona koszt.html zawiera: dwa pola numeryczne „Długość ogrodzenia [m]” i „Wysokość [m]”, trzy przyciski opcji „Siatka – 45 zł/m²”, „Panel – 80 zł/m²”, „Drewno – 120 zł/m²” (siatka domyślnie zaznaczona), przycisk „Oblicz” i pusty akapit pod przyciskiem.
Skrypt w JavaScript po kliknięciu: jeśli oba pola liczbowe są wypełnione – oblicza powierzchnię (długość × wysokość) oraz koszt (powierzchnia × cena wybranego materiału) i wypisuje: Powierzchnia ogrodzenia: <powierzchnia> m², koszt: <koszt> zł. W przeciwnym razie wypisuje: Wprowadź poprawne dane. Stosuj znaczące nazwy.
Kryteria samooceny (0/1):
- JavaScript, co najmniej jedna poprawna instrukcja, funkcja wywoływana przyciskiem.
- Pobranie danych z co najmniej jednej kontrolki.
- Powierzchnia = długość × wysokość.
- Koszt zależny od zaznaczonego materiału – poprawny dla dwóch różnych materiałów.
- Przy pustym którymkolwiek polu – komunikat
Wprowadź poprawne dane.zamiast wyniku. - Wynik w podanym formacie w akapicie pod przyciskiem.
- Znaczące nazwy.
Testy: (20, 1.5, panel) → Powierzchnia ogrodzenia: 30 m², koszt: 2400 zł; (10, 2, drewno) → 20 m², 2400 zł; (puste, 2, siatka) → Wprowadź poprawne dane.
Pokaż rozwiązanie
<label>Długość ogrodzenia [m]: <input type="number" id="dlugosc"></label><br>
<label>Wysokość [m]: <input type="number" id="wysokosc" step="0.1"></label><br>
<input type="radio" name="material" value="45" id="siatka" checked> <label for="siatka">Siatka – 45 zł/m²</label>
<input type="radio" name="material" value="80" id="panel"> <label for="panel">Panel – 80 zł/m²</label>
<input type="radio" name="material" value="120" id="drewno"> <label for="drewno">Drewno – 120 zł/m²</label><br>
<button type="button" id="oblicz">Oblicz</button>
<p id="wynik"></p>function obliczKosztOgrodzenia() {
const dlugosc = parseFloat(document.getElementById('dlugosc').value);
const wysokosc = parseFloat(document.getElementById('wysokosc').value);
const akapit = document.getElementById('wynik');
// kryterium 5: walidacja – puste pole daje NaN
if (isNaN(dlugosc) || isNaN(wysokosc)) {
akapit.textContent = 'Wprowadź poprawne dane.';
return;
}
// kryterium 3 i 4
const powierzchnia = dlugosc * wysokosc;
const cenaZaMetr = parseFloat(document.querySelector('input[name="material"]:checked').value);
const koszt = powierzchnia * cenaZaMetr;
// kryterium 6
akapit.textContent = `Powierzchnia ogrodzenia: ${powierzchnia} m², koszt: ${koszt} zł`;
}
document.getElementById('oblicz').addEventListener('click', obliczKosztOgrodzenia);Tu celowo styl nowoczesny (addEventListener, textContent, template string) – zwróć uwagę, że skrypt jest pod przyciskiem, więc getElementById('oblicz') go znajduje.
Nawóz do trawnika – zaokrąglanie (20 min)
Strona nawoz.html zawiera: pole numeryczne „Powierzchnia trawnika [m²]”, przycisk „Policz” i pusty akapit pod przyciskiem. Jeden worek nawozu wystarcza na 25 m², a kosztuje 39 zł.
Skrypt w JavaScript po kliknięciu pobiera powierzchnię, oblicza liczbę worków (powierzchnia / 25, zaokrąglona w górę do liczby całkowitej – nawóz sprzedaje się tylko w całych workach) i koszt (worki × 39 zł). W akapicie wypisuje, w dwóch liniach: Liczba worków: <worki> oraz Koszt: <koszt> zł. Stosuj znaczące nazwy.
Kryteria samooceny (0/1):
- JavaScript, co najmniej jedna poprawna instrukcja, funkcja wywoływana przyciskiem.
- Pobranie powierzchni z pola.
- Dzielenie powierzchni przez 25.
- Wynik zaokrąglony w górę do liczby całkowitej (dowolną metodą).
- Koszt = liczba worków × 39.
- Dwie linie w podanym formacie w akapicie pod przyciskiem – poprawne dla dwóch różnych powierzchni.
- Znaczące nazwy.
Testy: 100 m² → 4 worki, 156 zł; 101 m² → 5 worków, 195 zł; 25 m² → 1 worek, 39 zł.
Pokaż rozwiązanie
<label>Powierzchnia trawnika [m²]: <input type="number" id="powierzchnia" min="1" value="100"></label>
<button type="button" onclick="policzWorki()">Policz</button>
<p id="wynik"></p>function policzWorki() {
const powierzchnia = parseFloat(document.getElementById('powierzchnia').value);
const liczbaWorkow = Math.ceil(powierzchnia / 25); // kryteria 3 i 4: dzielenie + w górę
const koszt = liczbaWorkow * 39; // kryterium 5
document.getElementById('wynik').innerHTML =
'Liczba worków: ' + liczbaWorkow + '<br>Koszt: ' + koszt + ' zł'; // kryterium 6: dwie linie
}Bez Math.ceil dla 101 m² wyszłoby 4.04 worka – kryterium 4 stracone. Math.round dałoby 4 – też źle. Tylko Math.ceil (lub parseInt(x) + 1 dla niecałkowitych – ale po co kombinować).
Znajdź pięć błędów
Uczeń oddał poniższy skrypt do zadania „Nawóz do trawnika”. Skrypt nie działa albo działa źle. Znajdź pięć błędów (składnia, logika, kryteria) i popraw kod tak, by zdobył wszystkie kryteria z zadania 4.
<input type="number" id="powierzchnia">
<button onclick="policz">Policz</button>
<p id="wynik"></p>
<script>
function policz() {
var p = document.getElementById('powierzchnia').value;
var w = Math.round(p / 25);
var k = w + 39;
alert('Liczba worków: ' + w + '<br>Koszt: ' + k + ' zł');
}
</script>Pokaż rozwiązanie
Błędy:
onclick="policz"– brak nawiasów, funkcja nie zostanie wywołana. Poprawnie:onclick="policz()".var p = ....valuebez konwersji –pto napis. Tu dzielenie akurat go skonwertuje, ale to przypadek: przy pierwszym dodawaniu (np. dopłacie) dostałbyś sklejanie napisów. Konwertuj zawsze –parseFloat.Math.roundzamiastMath.ceil– 101 m² da 4 worki zamiast 5 (kryterium „w górę”).w + 39zamiastw * 39– koszt to liczba worków razy cena.alert(...)zamiast akapitu pod przyciskiem – kryterium miejsca; dodatkowo<br>w alercie wyświetli się dosłownie.- (bonus) Nazwy
p,w,k,policz– jednoliterowe zmienne kosztują kryterium nazewnictwa.
<label>Powierzchnia trawnika [m²]: <input type="number" id="powierzchnia" min="1" value="101"></label>
<button type="button" onclick="policzWorki()">Policz</button>
<p id="wynik"></p>function policzWorki() {
var powierzchnia = parseFloat(document.getElementById('powierzchnia').value); // 2: konwersja
var liczbaWorkow = Math.ceil(powierzchnia / 25); // 3: w górę
var koszt = liczbaWorkow * 39; // 4: mnożenie
document.getElementById('wynik').innerHTML = // 5: akapit, nie alert
'Liczba worków: ' + liczbaWorkow + '<br>Koszt: ' + koszt + ' zł';
}
// 1: w HTML onclick="policzWorki()" – z nawiasami; 6: znaczące nazwyTest powtórkowy
Test powtórkowy
Format jak w części pisemnej INF.03 – 4 odpowiedzi, 1 poprawna.
Który zapis w HTML poprawnie uruchomi funkcję oblicz po kliknięciu przycisku?
W polu wpisano 4. Co wypisze ten kod w dialekcie egzaminacyjnym?
var ilosc = document.getElementById('ilosc').value;
var cena = 10;
document.getElementById('wynik').innerHTML = 'Razem: ' + (ilosc + cena) + ' zł';Arkusz: „liczba puszek zaokrąglona w górę do liczby całkowitej”. Powierzchnia 37 m², 1 puszka na 4 m². Które wyrażenie spełnia kryterium?
Która właściwość wpisze tekst wyniku do pustego akapitu <p id='wynik'></p>?
Skrypt ma działać przy <script> umieszczonym w <head> bez atrybutu defer. Które podpięcie zdarzenia zadziała na pewno?
Arkusz wymaga wyniku „dla dwóch różnych miast z listy”. Co to oznacza dla twojego kodu?
Skrypt nie uruchamia się z powodu błędu składni. Które kryterium egzaminator może mimo to zaliczyć na podstawie kodu źródłowego?
Które nazwy spełniają kryterium „znaczące nazewnictwo zmiennych i funkcji”?
Pole liczbowe jest puste. Który warunek wykryje to po var w = parseFloat(pole.value);?
Co wypisze kod, gdy użytkownik zaznaczył checkbox #rabat?
var cena = 200;
if (document.getElementById('rabat').checked == true) {
cena = cena * 0.9;
}
document.getElementById('wynik').innerHTML = 'Cena: ' + cena + ' zł';