Dziennik krok 5: klasa Gradebook jako model
Projekt: dziennik ocen krok po kroku - JavaScript od podstaw: konsola (JavaScript)
Funkcje i dane, które zawsze idą w parze, trafiają do klasy. `Gradebook` trzyma oceny w prywatnym polu `#records` (nikt z zewnątrz nie dopisze złej oceny z pominięciem walidacji), a metody statyczne `parseLine` i `average` nie potrzebują konkretnego dziennika. `load` zwraca listę błędów zamiast je wypisywać, bo model nie decyduje, JAK pokazać wynik. Tym zajmuje się osobna funkcja `report` (widok). Program główny ma już tylko kilka linii.
const DATA = `Ola;matematyka;5
Jan;matematyka;3
Ola;polski;4
Ala;fizyka;7
Ewa;matematyka;6
Jan;polski;2
Kuba;matematyka
Ewa;polski;5
Ola;matematyka;6
Ola;polski;cztery
Jan;matematyka;4`;
class Gradebook {
#records = [];
static parseLine(line) {
const parts = line.split(';');
if (parts.length !== 3) throw new Error('oczekiwano 3 pól');
const [name, subject, gradeText] = parts.map(p => p.trim());
if (name === '' || subject === '') throw new Error('puste imię lub przedmiot');
const grade = Number(gradeText);
if (!Number.isInteger(grade) || grade < 1 || grade > 6) {
throw new Error(`ocena spoza skali 1-6: "${gradeText}"`);
}
return { name, subject, grade };
}
static average(grades) {
return grades.reduce((a, b) => a + b, 0) / grades.length;
}
add(record) {
this.#records.push(record);
}
load(text) {
const errors = [];
text.split('\n').forEach((line, i) => {
try {
this.add(Gradebook.parseLine(line));
} catch (e) {
errors.push(`wiersz ${i + 1}: ${e.message}`);
}
});
return errors;
}
gradesBy(key) {
const groups = {};
for (const r of this.#records) {
if (!(r[key] in groups)) groups[r[key]] = [];
groups[r[key]].push(r.grade);
}
return groups;
}
best() {
let best = null;
for (const [name, grades] of Object.entries(this.gradesBy('name'))) {
const avg = Gradebook.average(grades);
if (best === null || avg > best.avg) best = { name, avg };
}
return best;
}
get records() {
return [...this.#records];
}
}
function report(book) {
console.log('Uczniowie:');
for (const [name, grades] of Object.entries(book.gradesBy('name'))) {
console.log(`${name}: ${Gradebook.average(grades).toFixed(2)}`);
}
console.log('Przedmioty:');
for (const [subject, grades] of Object.entries(book.gradesBy('subject'))) {
console.log(`${subject}: ${Gradebook.average(grades).toFixed(2)} (ocen: ${grades.length})`);
}
const best = book.best();
console.log(`Najlepsza średnia: ${best.name} (${best.avg.toFixed(2)})`);
}
const book = new Gradebook();
for (const error of book.load(DATA)) {
console.log('Pominięto ' + error);
}
report(book);Ładowanie interaktywnego edytora... Jeśli się nie pojawi, włącz JavaScript.
Wszystkie lekcje kursu JavaScript od podstaw: konsola·Zaloguj się, aby zapisać postęp na koncie.