Aufwärmen · Aufgabe 1 von 7
Zum Aufwärmen aus Lektion B5.4: Was gibt dieser Code aus?
const items = JSON.parse('[{"qty": 2}, {"qty": 3}]');
console.log(items.length, items[1].qty);// B5.5 · ca. 38 Min. · Einstieg
Nach diesem Projekt laden Sie Datensätze aus JSON, summieren und filtern sie, berechnen Rabatt und MwSt. auf den Cent genau und speichern das Ergebnis wieder als JSON.
Lektion 5 von 5 in B5 Arrays, Objekte und JSON
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
const items = JSON.parse('[{"qty": 2}, {"qty": 3}]');
console.log(items.length, items[1].qty);Vorhersagen · Aufgabe 2 von 7
console.log(0.1 + 0.2 === 0.3, 10 + 20 === 30);Üben · Aufgabe 3 von 7
const subtotal = lines.reduce((sum, line) => sum + line.totalCents, ____);Üben · Aufgabe 4 von 7
Üben · Aufgabe 5 von 7
const items = [{ cat: "food", cents: 300 }, { cat: "home", cents: 500 }, { cat: "food", cents: 250 }];
const food = items.filter((i) => i.cat === "food").reduce((s, i) => s + i.cents, 0);
console.log(food);Denksport · Aufgabe 6 von 7
const prices = [0.1, 0.2, 0.3];
const total = prices.reduce((s, p) => s + p, 0);
console.log(total === 0.6, total.toFixed(2));Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.
Ausgearbeitetes Beispiel
Der Warenkorb kommt als JSON-Text mit vier Artikeln, jeder mit einem Preis in Cent. map macht die Zeilensummen, reduce die Zwischensumme, filter die food-Artikel mit 15 % Rabatt, und Math.round hält Rabatt und 19 % MwSt. in ganzen Cent. euro formatiert Cent nur für die Ausgabe. Die Zeile mit 0.1 + 0.2 zeigt den Grund: Euro als Dezimalzahlen driften ab, Cent nicht. Der Beleg wird wieder als JSON-Text gespeichert.
main.js
// Shopping-basket totals, worked in whole cents.
const text = `[
{"name": "Coffee", "category": "food", "priceCents": 899, "qty": 2},
{"name": "Milk", "category": "food", "priceCents": 119, "qty": 3},
{"name": "Soap", "category": "home", "priceCents": 249, "qty": 1},
{"name": "Sponges", "category": "home", "priceCents": 175, "qty": 4}
]`;
const euro = (cents) => `${(cents / 100).toFixed(2)} EUR`;
const basket = JSON.parse(text);
console.log(Array.isArray(basket), basket.length, "items");
const lines = basket.map(({ name, priceCents, qty }) => ({ name, qty, totalCents: priceCents * qty }));
for (const { name, qty, totalCents } of lines) {
console.log(`${qty} x ${name}: ${euro(totalCents)}`);
}
const subtotal = lines.reduce((sum, line) => sum + line.totalCents, 0);
console.log(`Subtotal: ${euro(subtotal)}`);
const food = basket.filter((item) => item.category === "food");
const foodCents = food.reduce((sum, item) => sum + item.priceCents * item.qty, 0);
const foodOffer = Math.round(foodCents * 85 / 100);
console.log(`Food: ${euro(foodCents)}, with 15% off: ${euro(foodOffer)}`);
const vat = Math.round(subtotal * 19 / 100);
console.log(`VAT 19%: ${euro(vat)}, total: ${euro(subtotal + vat)}`);
console.log(0.1 + 0.2, 10 + 20);
const receipt = { subtotalCents: subtotal, vatCents: vat, totalCents: subtotal + vat };
console.log(JSON.stringify(receipt, null, 2));
Ausführen mit
node main.jsAusgabe
true 4 items
2 x Coffee: 17.98 EUR
3 x Milk: 3.57 EUR
1 x Soap: 2.49 EUR
4 x Sponges: 7.00 EUR
Subtotal: 31.04 EUR
Food: 21.55 EUR, with 15% off: 18.32 EUR
VAT 19%: 5.90 EUR, total: 36.94 EUR
0.30000000000000004 30
{
"subtotalCents": 3104,
"vatCents": 590,
"totalCents": 3694
}Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Übung 1 von 3
loadBasket(text) soll JSON-Text parsen und das Array der Artikel zurückgeben, oder [], wenn der Text kein Array enthält. lineTotal(item) soll den Preis in Cent mal die Menge zurückgeben. subtotal(items) soll alle Zeilensummen addieren und für einen leeren Warenkorb 0 liefern. Der Starter vertraut dem Text, addiert die Menge zum Preis und ruft reduce ohne Startwert auf. Korrigieren Sie alle drei.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Führen Sie die Tests aus: lineTotal liefert 901 für 2 x 899, und subtotal([]) endet mit einem TypeError.
Prüfen Sie den geparsten Wert mit Array.isArray(data) ? data : [] und multiplizieren Sie in lineTotal.
Geben Sie reduce den Startwert: .reduce((sum, cents) => sum + cents, 0).
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// The items in the JSON text, or [] when it holds no array.
export function loadBasket(text) {
const data = JSON.parse(text);
return Array.isArray(data) ? data : [];
}
// One line: the price in cents times the quantity.
export function lineTotal(item) {
return item.priceCents * item.qty;
}
// Every line total added up, in cents; 0 for an empty basket.
export function subtotal(items) {
return items.map(lineTotal).reduce((sum, cents) => sum + cents, 0);
}
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// The items in the JSON text, or [] when it holds no array.
export function loadBasket(text) {
return JSON.parse(text);
}
// One line: the price in cents times the quantity.
export function lineTotal(item) {
return item.priceCents + item.qty;
}
// Every line total added up, in cents; 0 for an empty basket.
export function subtotal(items) {
return items.map(lineTotal).reduce((sum, cents) => sum + cents);
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {loadBasket, lineTotal, subtotal} from './main.js';
const TEXT = '[{"name": "Coffee", "category": "food", "priceCents": 899, "qty": 2}, {"name": "Milk", "category": "food", "priceCents": 119, "qty": 3}, {"name": "Soap", "category": "home", "priceCents": 249, "qty": 1}, {"name": "Sponges", "category": "home", "priceCents": 175, "qty": 4}]';
test('loadBasket gibt die vier Artikel zurück', () => {
const got = loadBasket(TEXT);
assert.equal(Array.isArray(got) && got.length, 4, 'loadBasket sollte ein Array mit 4 Artikeln zurückgeben, erhalten: ' + JSON.stringify(got));
});
test('loadBasket gibt [] zurück, wenn der Text ein Objekt enthält', () => {
const got = loadBasket('{"items": []}');
assert.deepEqual(got, [], 'loadBasket für ein Objekt sollte [] sein, erhalten: ' + JSON.stringify(got));
});
test('lineTotal multipliziert den Preis mit der Menge', () => {
const got = lineTotal({ name: 'Coffee', priceCents: 899, qty: 2 });
assert.equal(got, 1798, 'lineTotal für 2 x 899 Cent sollte 1798 sein, erhalten: ' + got);
});
test('subtotal addiert alle Zeilen', () => {
const got = subtotal(JSON.parse(TEXT));
assert.equal(got, 3104, 'subtotal des Warenkorbs sollte 3104 Cent sein, erhalten: ' + got);
});
test('subtotal eines leeren Warenkorbs ist 0', () => {
const got = subtotal([]);
assert.equal(got, 0, 'subtotal([]) sollte 0 sein, erhalten: ' + got);
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenÜbung 2 von 3
categoryTotal(items, category) soll nur die Zeilen einer Kategorie addieren, in Cent. discounted(cents, percent) soll den Betrag nach einem Rabatt zurückgeben und vatOf(netCents, rate) die MwSt. zum Satz rate Prozent; beides müssen ganze Cent sein, auf den nächsten gerundet. Der Starter summiert alle Kategorien, und Rabatt und MwSt. enthalten Bruchteile eines Cents. Korrigieren Sie das mit filter und Math.round.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Führen Sie die Tests aus: Die food-Summe enthält die home-Zeilen, und vatOf(1049, 19) liefert 199.31.
Setzen Sie .filter((item) => item.category === category) vor das reduce.
Packen Sie jede Rechnung in Math.round(…), damit das Ergebnis eine ganze Zahl von Cent ist.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// The total in cents of the lines in one category.
export function categoryTotal(items, category) {
return items
.filter((item) => item.category === category)
.reduce((sum, item) => sum + item.priceCents * item.qty, 0);
}
// cents after a discount of percent, in whole cents.
export function discounted(cents, percent) {
return Math.round(cents * (100 - percent) / 100);
}
// The VAT on netCents at rate percent, in whole cents.
export function vatOf(netCents, rate) {
return Math.round(netCents * rate / 100);
}
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// The total in cents of the lines in one category.
export function categoryTotal(items, category) {
return items.reduce((sum, item) => sum + item.priceCents * item.qty, 0);
}
// cents after a discount of percent, in whole cents.
export function discounted(cents, percent) {
return cents * (100 - percent) / 100;
}
// The VAT on netCents at rate percent, in whole cents.
export function vatOf(netCents, rate) {
return netCents * rate / 100;
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {categoryTotal, discounted, vatOf} from './main.js';
const TEXT = '[{"name": "Coffee", "category": "food", "priceCents": 899, "qty": 2}, {"name": "Milk", "category": "food", "priceCents": 119, "qty": 3}, {"name": "Soap", "category": "home", "priceCents": 249, "qty": 1}, {"name": "Sponges", "category": "home", "priceCents": 175, "qty": 4}]';
test('categoryTotal addiert nur die food-Zeilen', () => {
const got = categoryTotal(JSON.parse(TEXT), 'food');
assert.equal(got, 2155, 'die food-Summe sollte 2155 Cent sein, erhalten: ' + got);
});
test('categoryTotal addiert nur die home-Zeilen', () => {
const got = categoryTotal(JSON.parse(TEXT), 'home');
assert.equal(got, 949, 'die home-Summe sollte 949 Cent sein, erhalten: ' + got);
});
test('discounted rundet auf einen ganzen Cent', () => {
const got = discounted(1999, 15);
assert.equal(got, 1699, 'discounted(1999, 15) sollte 1699 sein, erhalten: ' + got);
});
test('vatOf rundet auf einen ganzen Cent', () => {
assert.equal(vatOf(1049, 19), 199, 'vatOf(1049, 19) sollte 199 sein, erhalten: ' + vatOf(1049, 19));
assert.equal(vatOf(3104, 19), 590, 'vatOf(3104, 19) sollte 590 sein, erhalten: ' + vatOf(3104, 19));
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenÜbung 3 von 3
formatEuro(cents) soll den Betrag in Euro mit zwei Nachkommastellen und der Währung zurückgeben, etwa 12.50 EUR. toReceipt(items) soll JSON-Text zurückgeben, um zwei Leerzeichen eingerückt, von einem Objekt mit lines, jede { name, totalCents }, und der totalCents aller Zeilen. Der Starter gibt 12.5 EUR aus und speichert die rohen Artikel. Korrigieren Sie das mit toFixed, einem Template-Literal, map, reduce und JSON.stringify.
Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.
Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.
Führen Sie die Tests aus: formatEuro(1250) liefert 12.5 EUR, weil eine Zahl ihre Null am Ende nicht behält.
Formatieren Sie mit einem Template-Literal: `${(cents / 100).toFixed(2)} EUR`.
Bauen Sie lines mit map, addieren Sie deren totalCents mit reduce ab 0 und rufen Sie dann JSON.stringify({ lines, totalCents }, null, 2) auf.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
// "12.50 EUR" for 1250 cents.
export function formatEuro(cents) {
return `${(cents / 100).toFixed(2)} EUR`;
}
// JSON text, indented by two spaces, of { lines: [{ name, totalCents }], totalCents }.
export function toReceipt(items) {
const lines = items.map(({ name, priceCents, qty }) => ({ name, totalCents: priceCents * qty }));
const totalCents = lines.reduce((sum, line) => sum + line.totalCents, 0);
return JSON.stringify({ lines, totalCents }, null, 2);
}
Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.
main.js
// "12.50 EUR" for 1250 cents.
export function formatEuro(cents) {
return cents / 100 + " EUR";
}
// JSON text, indented by two spaces, of { lines: [{ name, totalCents }], totalCents }.
export function toReceipt(items) {
return JSON.stringify(items);
}
main.test.js
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {formatEuro, toReceipt} from './main.js';
test('formatEuro zeigt zwei Nachkommastellen und die Währung', () => {
assert.equal(formatEuro(1250), '12.50 EUR', 'formatEuro(1250) sollte "12.50 EUR" sein, erhalten: ' + JSON.stringify(formatEuro(1250)));
assert.equal(formatEuro(3104), '31.04 EUR', 'formatEuro(3104) sollte "31.04 EUR" sein, erhalten: ' + JSON.stringify(formatEuro(3104)));
});
test('formatEuro zeigt 5 Cent als 0.05 EUR', () => {
assert.equal(formatEuro(5), '0.05 EUR', 'formatEuro(5) sollte "0.05 EUR" sein, erhalten: ' + JSON.stringify(formatEuro(5)));
});
test('toReceipt enthält die Zeilensummen und die Gesamtsumme', () => {
const items = [{ name: 'Tea', category: 'food', priceCents: 349, qty: 2 }, { name: 'Soap', category: 'home', priceCents: 249, qty: 1 }];
const got = JSON.parse(toReceipt(items));
const expected = { lines: [{ name: 'Tea', totalCents: 698 }, { name: 'Soap', totalCents: 249 }], totalCents: 947 };
assert.deepEqual(got, expected, 'toReceipt sollte ' + JSON.stringify(expected) + ' enthalten, erhalten: ' + JSON.stringify(got));
});
test('toReceipt ist um zwei Leerzeichen eingerückt', () => {
const got = toReceipt([{ name: 'Tea', category: 'food', priceCents: 349, qty: 2 }]);
assert.match(got, /^[{]\n "lines": /, 'toReceipt sollte mit {, einem Zeilenumbruch und zwei Leerzeichen vor "lines" beginnen, erhalten: ' + JSON.stringify(got));
});
package.json
{
"type": "module"
}
package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.
Programm ausführen:
node main.jsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
node --testlearnrun.js herunterladenconst basket = [];
const subtotal = basket.reduce((sum, cents) => sum + cents);
console.log(subtotal);
Was Node.js ausgibt
TypeError: Reduce of empty array with no initial valueWarum, und die Lösung
Ohne Startwert beginnt reduce mit dem ersten Eintrag, und ein leeres Array hat keinen. Ein Warenkorb kann leer sein, also geben Sie immer den Startwert an: basket.reduce((sum, cents) => sum + cents, 0) liefert 0. Der Startwert hält die Summe auch dann als Zahl, wenn die Einträge Objekte sind.
const text = '[{"name": "Tea", "priceCents": 349, "qty": 2}]';
const lines = text.map((item) => item.priceCents * item.qty);
console.log(lines);
Was Node.js ausgibt
TypeError: text.map is not a functionWarum, und die Lösung
text ist ein String mit JSON darin, und Strings haben keine map-Methode. Parsen Sie zuerst: const basket = JSON.parse(text);, prüfen Sie es mit Array.isArray(basket) und rufen Sie dann basket.map(…) auf.
const item = JSON.parse('{"name": "Tea", "price": "3.49"}');
console.log(item.price.toFixed(2));
Was Node.js ausgibt
TypeError: item.price.toFixed is not a functionWarum, und die Lösung
Im JSON steht "3.49" in Anführungszeichen, also liefert JSON.parse einen String, und toFixed gibt es nur bei Zahlen. Speichern Sie Beträge als JSON-Zahlen, und zwar in ganzen Cent: {"priceCents": 349}. Bei Daten, die Sie nicht ändern können, wandeln Sie zuerst mit Number(item.price) um und prüfen, dass das Ergebnis nicht NaN ist.
JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.