简易计算器
用 JavaScript 写一个能连续运算的计算器。表面是按钮 + 显示屏,里子是三个状态之间的小型状态机。
看起来最简单,藏着状态管理的第一课
「12 + 5 = 17,再按 × 3」这个连算怎么处理?按 5 之前要不要先清屏?连续按两次加号会不会出错?这些细节逼着你开始用「状态」思考:屏幕显示什么、当前在等什么、按下去的按钮是数字还是运算符。这是第一次接触状态机的雏形,比写之前所有的项目都更训练逻辑。
分四步做一个不傻的计算器
难点全在「连续按运算符」与「按等号之后继续算」这两个边界,其他都是表面功夫。
画界面:显示屏 + 按钮网格
用一个 div 当显示屏,下面用 display: grid; grid-template-columns: repeat(4, 1fr); 排 16 个按钮:0-9、加减乘除、等号、清除、小数点。每个按钮加 data-action="num|op|eq|clear|dot" 与 data-value 属性,方便后面用事件委托统一处理。
定义三个状态变量
核心:current(当前显示屏上的字符串)、previous(上一次输入的数)、operator(当前运算符,null 表示还没选)。所有按钮的点击都只是在「改这三个变量 + 重新渲染 current」。
处理运算符按钮
按运算符时:如果 previous 为空,把 current 存进 previous,清空 current;如果 previous 已有值且 current 也非空,先算出 previous operator current 的结果,存进 previous,再记下新运算符。这就是「连算」的关键——每次按运算符都先把前面的算掉。
等号、清除与小数点
等号:算出 previous operator current,结果显示出来后把 previous 清空(这样再按数字会开始新算式)。清除:三个状态全置空。小数点:如果 current 里已经有 . 就忽略,否则追加。处理完这四个边界,计算器就比大多数人手机自带的还耐造了。
关键代码片段
四个状态变量 + 一个事件委托,足以撑起一个完整计算器。
let current = '', previous = null, operator = null; const screen = document.querySelector('.screen'); function compute(a, op, b) { switch (op) { case '+': return a + b; case '-': return a - b; case '×': return a * b; case '÷': return b === 0 ? 'Error' : a / b; } } document.querySelector('.pad').addEventListener('click', e => { const btn = e.target.closest('button'); if (!btn) return; const { action, value } = btn.dataset; if (action === 'num') { current = current === '0' ? value : current + value; } else if (action === 'dot') { if (!current.includes('.')) current = (current || '0') + '.'; } else if (action === 'op') { if (previous !== null && current) { previous = compute(previous, operator, parseFloat(current)); } else { previous = parseFloat(current); } operator = value; current = ''; } else if (action === 'eq') { if (previous !== null && operator && current) { current = String(compute(previous, operator, parseFloat(current))); previous = null; operator = null; } } else if (action === 'clear') { current = ''; previous = null; operator = null; } screen.textContent = current || '0'; });
计算器教给我一件事:越是看起来「就那点功能」的项目,越要在动手前把状态画清楚。三个变量 + 一个事件函数,全靠「按下每个按钮后这三个变量分别变成什么」这张表撑着。后来写 Redux、写 React reducer,本质都是同一张状态转移表,只是粒度更细。
继续下一个案例
状态管理练完,下一步进入现代浏览器 API,用 IntersectionObserver 做图片懒加载。