
🧮 Einfacher JavaScript-taschenrechner: schritt-für-schritt-anleitung
Benötigen Sie einen einfachen Rechner auf Ihrer Website, einen Versandkostenrechner, einen Hypothekenrechner oder einfach nur „etwas spontan berechnen"? Ein Backend dafür zu schreiben, ist, als würde man mit Kanonen auf Spatzen schießen. JavaScript auf dem Client erledigt das an einem Abend.
Das Problem der meisten Anleitungen: Sie liefern eine jQuery-Version von 2017 mit eval(), und das ist eine Sicherheitslücke, von der sie Ihnen nichts sagen. Wir gehen einen anderen Weg: Wir bauen einen Rechner in reinem JavaScript, mit ordentlichem Layout und ohne die „Installiere drei Abhängigkeiten"-Agenda.
Am Ende dieses Artikels haben Sie funktionierenden Code, der addiert, subtrahiert, multipliziert und dividiert, sowie ein Verständnis dafür, warum man eval() besser vermeidet.
💡 Kurzer Überblick:
- HTML: Rechner-Markup mit CSS Grid aufbauen, kein table und center
- CSS: responsives Grid, Button-Styling und Display hinzufügen
- JavaScript: Klick-Erfassung, Ausdruckssammlung und Berechnung ohne eval() schreiben
- Sicherheit: lernen, womit man eval() ersetzt und warum das wichtig ist
Schritt 1: HTML, Rechner-Markup
Zuerst bauen wir das Grundgerüst. Kein <center> und <table border="4"> von 2005, wir verwenden CSS Grid: vier Spalten für Ziffern und Operatoren plus eine Anzeigezeile oben.
Erstellen Sie eine index.html-Datei und fügen Sie dieses Markup hinzu:
1 <div class="calculator"> 2 <input class="display" type="text" readonly> 3 4 <div class="buttons"> 5 <button class="btn-clear" data-action="clear">C</button> 6 <button class="btn-operator" data-action="operator" data-value="/">/</button> 7 <button class="btn-operator" data-action="operator" data-value="*">*</button> 8 <button class="btn-operator" data-action="operator" data-value="-">-</button> 9 10 <button class="btn-number" data-action="number" data-value="7">7</button> 11 <button class="btn-number" data-action="number" data-value="8">8</button> 12 <button class="btn-number" data-action="number" data-value="9">9</button> 13 <button class="btn-operator" data-action="operator" data-value="+">+</button> 14 15 <button class="btn-number" data-action="number" data-value="4">4</button> 16 <button class="btn-number" data-action="number" data-value="5">5</button> 17 <button class="btn-number" data-action="number" data-value="6">6</button> 18 <button class="btn-equals" data-action="calculate">=</button> 19 20 <button class="btn-number" data-action="number" data-value="1">1</button> 21 <button class="btn-number" data-action="number" data-value="2">2</button> 22 <button class="btn-number" data-action="number" data-value="3">3</button> 23 <button class="btn-number btn-zero" data-action="number" data-value="0">0</button> 24 </div> 25 </div>
Hier ist das Display (<input>) schreibgeschützt: Der Nutzer gibt Daten nicht über die Tastatur ein, sondern klickt auf Buttons. Das schützt vor ungültigen Zeichen im Ausdruck. Die Buttons sind durch data-action-Attribute unterteilt: "number", "operator", "calculate" und "clear", damit das Skript weiß, was es mit einem Klick tun soll. Das data-value-Attribut speichert den Button-Wert: eine Ziffer oder ein Operationszeichen.
Hinweis: Das Display hat ein readonly-Attribut, der Nutzer kann dort nicht alert('hack') über die Tastatur eingeben.
Schritt 2: CSS, Erscheinungsbild
Nun die Stile. Ohne CSS sieht der Rechner wie ein Stapel Buttons aus, das Grid behebt alles. Fügen Sie in derselben index.html innerhalb von <head> Folgendes hinzu:
1 <style> 2 .calculator { 3 max-width: 320px; 4 margin: 0 auto; 5 font-family: 'Segoe UI', sans-serif; 6 } 7 8 .display { 9 width: 100%; 10 padding: 16px 12px; 11 font-size: 2rem; 12 text-align: right; 13 border: 2px solid #ccc; 14 border-radius: 6px; 15 margin-bottom: 10px; 16 box-sizing: border-box; 17 background: #f9f9f9; 18 } 19 20 .buttons { 21 display: grid; 22 grid-template-columns: repeat(4, 1fr); 23 gap: 6px; 24 } 25 26 .buttons button { 27 padding: 18px 0; 28 font-size: 1.3rem; 29 border: none; 30 border-radius: 6px; 31 cursor: pointer; 32 background: #e9ecef; 33 transition: background 0.15s; 34 } 35 36 .buttons button:hover { 37 background: #dee2e6; 38 } 39 40 .btn-operator { 41 background: #ff922b !important; 42 color: #fff; 43 } 44 45 .btn-operator:hover { 46 background: #f76707 !important; 47 } 48 49 .btn-equals { 50 background: #228be6 !important; 51 color: #fff; 52 } 53 54 .btn-equals:hover { 55 background: #1971c2 !important; 56 } 57 58 .btn-clear { 59 background: #fa5252 !important; 60 color: #fff; 61 } 62 63 .btn-clear:hover { 64 background: #e03131 !important; 65 } 66 67 .btn-zero { 68 grid-column: span 2; 69 } 70 </style>
Das Grid grid-template-columns: repeat(4, 1fr) ergibt eine gleichmäßige Tastatur mit vier Spalten, die Buttons verteilen sich selbst. Der Button "0" wird über grid-column: span 2 über zwei Spalten gestreckt, eine übliche Technik für das Rechner-Layout.
Die Farben sind hier funktional: Orange für Operatoren, Blau für „Gleich", Rot für Zurücksetzen. Der Nutzer erfasst den Zweck des Buttons sofort, bevor er den Text liest.
Schritt 3: JavaScript, Logik ohne eval()
Der Hauptteil. Binden wir das Skript am Ende von <body> in derselben index.html ein:
1 <script> 2 const display = document.querySelector('.display'); 3 4 let expression = ''; 5 6 document.querySelector('.buttons').addEventListener('click', function (e) { 7 const btn = e.target.closest('button'); 8 if (!btn) return; 9 10 const action = btn.dataset.action; 11 12 if (action === 'number') { 13 expression += btn.dataset.value; 14 display.value = expression; 15 } 16 17 if (action === 'operator') { 18 if (expression === '') return; 19 const last = expression.slice(-1); 20 if (['+', '-', '*', '/'].includes(last)) return; 21 expression += btn.dataset.value; 22 display.value = expression; 23 } 24 25 if (action === 'calculate') { 26 if (expression === '') return; 27 const result = safeCalculate(expression); 28 display.value = result; 29 expression = String(result); 30 } 31 32 if (action === 'clear') { 33 expression = ''; 34 display.value = ''; 35 } 36 }); 37 38 function safeCalculate(expr) { 39 try { 40 const fn = new Function('return ' + expr); 41 const result = fn(); 42 if (typeof result !== 'number' || !isFinite(result)) { 43 return 'Error'; 44 } 45 return Math.round(result * 1e10) / 1e10; 46 } catch (e) { 47 return 'Error'; 48 } 49 } 50 </script>
Lassen Sie uns Zeile für Zeile aufschlüsseln, was hier passiert.
Klick-Erfassung. addEventListener wird nicht an jeden Button, sondern an den .buttons-Container angehängt, das ist Event-Delegation. Bei einem Klick findet e.target.closest('button') den nächstgelegenen Button (auch wenn Sie auf Text darin geklickt haben). btn.dataset.action liest das data-action-Attribut aus, und dann verzweigt die Logik.
Ausdruckssammlung. Jeder Zifferndruck hängt diese an den expression-String an. Ein Operator wird nur angehängt, wenn der Ausdruck nicht leer ist und das letzte Zeichen kein Operator ist (Schutz gegen doppeltes ++ und */). Das Display aktualisiert sich bei jedem Tastendruck, der Nutzer sieht den gesamten String, wie bei einem echten Taschenrechner.
Berechnung. Anstelle von eval() der new Function()-Konstruktor. Auch er führt einen String als Code aus, aber mit einem Unterschied: eval() hat Zugriff auf den lokalen Gültigkeitsbereich, während Function nur Zugriff auf den globalen Gültigkeitsbereich hat. Das ist kein Allheilmittel, aber für einen clientseitigen Rechner, bei dem der Nutzer den Ausdruck selbst eingibt, ein ausreichendes Maß an Isolation. Nach der Berechnung wird das Ergebnis auf 10 Dezimalstellen gerundet, sonst wird aus 0.1 + 0.2 nämlich 0.30000000000000004.
Zurücksetzen. Der "C"-Button setzt sowohl expression als auch das Display auf Null.
Narrenschutz. Wenn der Ausdruck leer ist, werden calculate und operator stillschweigend ignoriert. Division durch Null ergibt Infinity, isFinite() fängt dies ab und gibt "Error" aus.
Schritt 4: Alles zusammenfügen
Kombinieren wir die drei Teile in einer Datei. Hier ist die vollständige index.html, die im Browser geöffnet werden kann:
1 <!DOCTYPE html> 2 <html lang="ru"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>JavaScript Calculator</title> 7 <style> 8 .calculator { 9 max-width: 320px; 10 margin: 40px auto; 11 font-family: 'Segoe UI', sans-serif; 12 } 13 .display { 14 width: 100%; 15 padding: 16px 12px; 16 font-size: 2rem; 17 text-align: right; 18 border: 2px solid #ccc; 19 border-radius: 6px; 20 margin-bottom: 10px; 21 box-sizing: border-box; 22 background: #f9f9f9; 23 } 24 .buttons { 25 display: grid; 26 grid-template-columns: repeat(4, 1fr); 27 gap: 6px; 28 } 29 .buttons button { 30 padding: 18px 0; 31 font-size: 1.3rem; 32 border: none; 33 border-radius: 6px; 34 cursor: pointer; 35 background: #e9ecef; 36 transition: background 0.15s; 37 } 38 .buttons button:hover { background: #dee2e6; } 39 .btn-operator { background: #ff922b !important; color: #fff; } 40 .btn-operator:hover { background: #f76707 !important; } 41 .btn-equals { background: #228be6 !important; color: #fff; } 42 .btn-equals:hover { background: #1971c2 !important; } 43 .btn-clear { background: #fa5252 !important; color: #fff; } 44 .btn-clear:hover { background: #e03131 !important; } 45 .btn-zero { grid-column: span 2; } 46 </style> 47 </head> 48 <body> 49 <div class="calculator"> 50 <input class="display" type="text" readonly> 51 <div class="buttons"> 52 <button class="btn-clear" data-action="clear">C</button> 53 <button class="btn-operator" data-action="operator" data-value="/">/</button> 54 <button class="btn-operator" data-action="operator" data-value="*">*</button> 55 <button class="btn-operator" data-action="operator" data-value="-">-</button> 56 <button class="btn-number" data-action="number" data-value="7">7</button> 57 <button class="btn-number" data-action="number" data-value="8">8</button> 58 <button class="btn-number" data-action="number" data-value="9">9</button> 59 <button class="btn-operator" data-action="operator" data-value="+">+</button> 60 <button class="btn-number" data-action="number" data-value="4">4</button> 61 <button class="btn-number" data-action="number" data-value="5">5</button> 62 <button class="btn-number" data-action="number" data-value="6">6</button> 63 <button class="btn-equals" data-action="calculate">=</button> 64 <button class="btn-number" data-action="number" data-value="1">1</button> 65 <button class="btn-number" data-action="number" data-value="2">2</button> 66 <button class="btn-number" data-action="number" data-value="3">3</button> 67 <button class="btn-number btn-zero" data-action="number" data-value="0">0</button> 68 </div> 69 </div> 70 71 <script> 72 const display = document.querySelector('.display'); 73 let expression = ''; 74 document.querySelector('.buttons').addEventListener('click', function (e) { 75 const btn = e.target.closest('button'); 76 if (!btn) return; 77 const action = btn.dataset.action; 78 if (action === 'number') { 79 expression += btn.dataset.value; 80 display.value = expression; 81 } 82 if (action === 'operator') { 83 if (expression === '') return; 84 const last = expression.slice(-1); 85 if (['+', '-', '*', '/'].includes(last)) return; 86 expression += btn.dataset.value; 87 display.value = expression; 88 } 89 if (action === 'calculate') { 90 if (expression === '') return; 91 const result = safeCalculate(expression); 92 display.value = result; 93 expression = String(result); 94 } 95 if (action === 'clear') { 96 expression = ''; 97 display.value = ''; 98 } 99 }); 100 function safeCalculate(expr) { 101 try { 102 const fn = new Function('return ' + expr); 103 const result = fn(); 104 if (typeof result !== 'number' || !isFinite(result)) return 'Error'; 105 return Math.round(result * 1e10) / 1e10; 106 } catch (e) { 107 return 'Error'; 108 } 109 } 110 </script> 111 </body> 112 </html>
Speichern Sie sie, öffnen Sie sie im Browser, der Rechner funktioniert sofort, kein Server, kein npm install. In der Praxis reicht dieser Code für einen Versandkostenrechner auf einer Landingpage oder ein Rabattberechnungsformular.

Warum nicht eval(): Sicherheit, die Einsteiger-Anleitungen nicht erwähnen
Wenn Sie alte Tutorials gelesen haben, haben Sie wahrscheinlich eval(expression) gesehen. Ja, es funktioniert. Aber das Problem ist, dass eval() jeden JavaScript-Code ausführt, der als String übergeben wird. Wenn alert(document.cookie) ins Display gelangt, wird es ausgeführt. Und wenn das Display für manuelle Eingaben offen ist, können Sie dort etwas Ernsteres einfügen.
In unserem Fall arbeitet das Display im readonly-Modus, der Ausdruck wird nur durch Klicken auf Buttons zusammengestellt. Das Risiko ist minimal. Aber die Gewohnheit, eval() zu verwenden, ist schlecht: Eines Tages kopieren Sie dieses Muster in ein Formular mit Benutzereingaben und erhalten eine XSS-Lücke.
Es gibt drei Alternativen, in aufsteigender Komplexität:
Ansatz | Schutz | Komplexität |
|---|---|---|
| Sieht keine lokalen Variablen, nur globale | Minimal |
Manueller Parser (String nach Operatoren parsen) | Volle Kontrolle über den Ausdruck | Mittel |
Web Worker mit isoliertem Kontext | Ausdruck berührt das DOM überhaupt nicht | Hoch |
Für einen Übungsrechner und die meisten realen Szenarien reicht new Function() mit Ergebnisverifikation aus. Aber wenn Sie einen Rechner in ein E-Commerce-Formular einbetten (Preis × Menge), geben Sie sich gar nicht erst mit String-Parsing ab: Nehmen Sie Werte aus Feldern und berechnen Sie direkt: priceInput.value * qtyInput.value. Dort wird überhaupt kein eval benötigt.
Wie man erweitert: Tastatureingabe und Operationsketten
Wenn die Basisversion funktioniert, fügen Sie zwei Funktionen hinzu, die aus einem Werkstück ein Werkzeug machen:
Tastatureingabe. Hängen Sie addEventListener('keydown', ...) an document und ordnen Sie Tasten den Buttons zu: Ziffern und Punkt zu data-action="number", Enter zu "equals", Escape zu "C", +-*/ zu Operatoren. Ignorieren Sie Buchstaben und Sonderzeichen.
Operationsketten. Im Moment berechnet unser Rechner „alles auf einmal". Aber wenn Sie 5 + 3 = drücken und dann * 2, macht er nicht weiter, der Ausdruck ist bereits auf das Ergebnis zurückgesetzt. Das lässt sich einfach beheben: Nach = überschreiben Sie expression nicht, sondern speichern das letzte Ergebnis in einer separaten lastResult-Variable. Beginnen Sie beim nächsten Operator den Ausdruck mit lastResult.
Beide Verbesserungen umfassen jeweils 15-20 Codezeilen. Probieren Sie sie selbst als Übung aus: Es ist der beste Weg zu verstehen, dass ein Rechner kein „Übungsprojekt", sondern eine normale technische Mini-Aufgabe ist.
⁉️🤔 Häufig gestellte Fragen
Geht es auch ganz ohne JavaScript?
Für die vier Grundrechenarten auf dem Client: nein. HTML und CSS sind Markup und Stile, sie rechnen nicht. Serverseitige Berechnung per PHP bedeutet, die Seite bei jedem „="-Druck neu zu laden. JavaScript ist hier die einzige praktikable Option. Es gibt CSS-Tricks mit
calc()und Checkboxen, die Logik imitieren, aber das ist eine Attraktion, kein Rechner: maximal eine Operation, kein Reset, mit schrecklichem Code.
Wie unterscheidet sich dieser Ansatz von „nimm ein fertiges npm-Paket"?
Keine einzige Abhängigkeit.
npm install calculator-libzieht 40 weitere Pakete, einen Bundler und ein halbes Megabyte Bundle nach sich, um zwei Zahlen zu addieren. Unsere Variante: eine HTML-Datei, 90 Zeilen JavaScript, läuft in jedem Browser ohne Server. Für die meisten typischen Aufgaben, einen Versandkostenrechner, eine Hypothekenberechnung auf einer Landingpage, ein „Kosten berechnen"-Formular, reicht das aus.
Warum nicht jQuery?
jQuery für einen Rechner ist wie ein Kleinbus für ein Brot. 2017 ergab das noch Sinn:
$('.btn')ist kürzer alsdocument.querySelectorAll('.btn'), und Browser verhielten sich unterschiedlich. Heute funktionierenaddEventListenerundclosest()in allen Browsern gleich, und 87 KB komprimiertes jQuery für fünf Klick-Handler mitzuschleppen, ist übertrieben. Wenn jQuery bereits im Projekt ist, nutzen Sie es, aber für neuen Code schreiben Sie in reinem JS.
Was tun mit Fließkommazahlen? 0.1 + 0.2 ergibt immer noch 0.30000000000000004.
Im Code haben wir
Math.round(result * 1e10) / 1e10gesetzt, das entfernt den Rest für zehn Stellen. Für finanzielle Berechnungen (Preise, Prozente) verwenden Sie Ganzzahlen, rechnen Sie in Cent, nicht in Euro:(100 + 200) / 100 = 3.00anstelle von0.1 + 0.2. Hier werden keinevalundFunctionbenötigt, nehmen Sie einfach Zahlen aus Feldern und addieren Sie sie.
Sollten Sie Ihren eigenen Rechner schreiben oder einen fertigen nehmen?
Wenn Sie einen Rechner für eine Seite benötigen, schreiben Sie ihn selbst in einer Stunde mit dieser Anleitung. Der Code umfasst weniger als 100 Zeilen, null Abhängigkeiten, Sie kontrollieren das Verhalten.
Wenn Sie eine Berechnung in WooCommerce oder ein Bestellformular einbetten, schreiben Sie keinen Ausdrucksparser. Nehmen Sie Werte aus Eingabefeldern und berechnen Sie direkt: total = basePrice + optionsSum. Das ist zuverlässiger, einfacher und sicherer als jede String-Berechnung.
Der Code aus dem Artikel ist eine funktionierende Grundlage. Ändern Sie das Layout, fügen Sie Prozente, Speicher (M+/M-/MR-Tasten), einen Operationsverlauf hinzu. Schreiben Sie einmal einen Rechner mit Ihren eigenen Händen, und die Frage „Wie funktioniert das?" ist für immer geklärt.



