You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自制JavaScript计算器中实现多运算串联及优先级支持?

JavaScript计算器:修复连续运算与优先级问题 + 代码优化

问题根源分析

原代码的核心缺陷:

  • 连续运算逻辑错误:chosenOperator被覆盖为单个运算函数,reduce仅能处理两个操作数,无法支持多步连续运算
  • 无运算优先级:所有运算按输入顺序执行,不遵循乘除优先的数学规则
  • 状态管理冗余:多个临时数组(tempExpression、tempExpressionFiltered等)增加复杂度,且数据与屏幕显示易不同步
  • 交互漏洞:小数点处理仅标记禁用但未实际阻止重复输入,删除操作时数据状态与屏幕内容不匹配

重构后的完整代码

HTML(修正嵌套结构,统一数据属性)

<p>CALCULATOR</p>
<div class="container">
  <div class="screen">
    <div class="previous-operand"></div>
    <div class="current-operand"></div>
  </div>
  <div class="row">
    <button type="button" data-action="delete">delete</button>
    <button type="button" data-action="clear">clear</button>
  </div>
  <div class="row">
    <button type="button" data-action="number">7</button>
    <button type="button" data-action="number">8</button>
    <button type="button" data-action="number">9</button>
    <button type="button" data-action="operator">/</button>
  </div>
  <div class="row">
    <button type="button" data-action="number">4</button>
    <button type="button" data-action="number">5</button>
    <button type="button" data-action="number">6</button>
    <button type="button" data-action="operator">*</button>
  </div>
  <div class="row">
    <button type="button" data-action="number">1</button>
    <button type="button" data-action="number">2</button>
    <button type="button" data-action="number">3</button>
    <button type="button" data-action="operator">-</button>
  </div>
  <div class="row">
    <button type="button" data-action="number">0</button>
    <button type="button" data-action="decimal">.</button>
    <button type="button" data-action="equals">=</button>
    <button type="button" data-action="operator">+</button>
  </div>
</div>

CSS(优化布局与显示效果)

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.container {
  width: 200px;
  margin: 1rem;
}

.screen {
  background-color: lightgray;
  width: 100%;
  height: 60px;
  padding: 0.5rem;
  text-align: right;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.previous-operand {
  font-size: 0.9rem;
  opacity: 0.7;
}

.current-operand {
  font-size: 1.2rem;
}

button {
  width: 50px;
  height: 50px;
  border: 1px solid #ddd;
  cursor: pointer;
  font-size: 1rem;
}

button:hover {
  background-color: #f0f0f0;
}

.row {
  display: flex;
}

JavaScript(核心逻辑重构)

// DOM元素获取
const screen = document.querySelector('.screen');
const previousOperandEl = screen.querySelector('.previous-operand');
const currentOperandEl = screen.querySelector('.current-operand');
const buttons = document.querySelectorAll('button');

// 计算器核心状态
let currentOperand = '';
let previousOperand = '';
let operation = undefined;
let expression = []; // 存储完整运算序列:[数字, 操作符, 数字, ...]

// 运算函数映射
const operations = {
  '+': (a, b) => a + b,
  '-': (a, b) => a - b,
  '*': (a, b) => a * b,
  '/': (a, b) => b !== 0 ? a / b : 'Error'
};

// 更新屏幕显示
function updateDisplay() {
  currentOperandEl.textContent = currentOperand || '0';
  previousOperandEl.textContent = operation ? `${previousOperand} ${operation}` : '';
}

// 追加数字/小数点
function appendNumber(value) {
  if (value === '.' && currentOperand.includes('.')) return;
  currentOperand += value;
  updateDisplay();
}

// 选择操作符
function chooseOperator(op) {
  if (currentOperand === '') return;
  // 已有未完成运算时,先计算前一步
  if (previousOperand !== '') compute();
  operation = op;
  previousOperand = currentOperand;
  expression.push(parseFloat(currentOperand), op);
  currentOperand = '';
  updateDisplay();
}

// 核心计算:处理运算优先级
function compute() {
  if (currentOperand === '') return;
  expression.push(parseFloat(currentOperand));
  
  // 第一步:计算所有乘除
  let temp = [];
  for (let i = 0; i < expression.length; i++) {
    if (expression[i] === '*' || expression[i] === '/') {
      const prev = temp.pop();
      const next = expression[i + 1];
      temp.push(operations[expression[i]](prev, next));
      i++; // 跳过已计算的下一个数字
    } else {
      temp.push(expression[i]);
    }
  }
  
  // 第二步:计算所有加减
  let result = temp[0];
  for (let i = 1; i < temp.length; i += 2) {
    result = operations[temp[i]](result, temp[i + 1]);
  }
  
  // 更新状态,支持连续运算
  currentOperand = result.toString();
  previousOperand = '';
  operation = undefined;
  expression = [result]; // 将结果作为下一次运算的起始
  updateDisplay();
}

// 清除所有状态
function clearAll() {
  currentOperand = '';
  previousOperand = '';
  operation = undefined;
  expression = [];
  updateDisplay();
}

// 删除最后一位输入
function deleteLast() {
  currentOperand = currentOperand.slice(0, -1);
  updateDisplay();
}

// 绑定按钮事件
buttons.forEach(button => {
  button.addEventListener('click', () => {
    const action = button.dataset.action;
    const value = button.textContent;
    
    switch(action) {
      case 'number':
      case 'decimal':
        appendNumber(value);
        break;
      case 'operator':
        chooseOperator(value);
        break;
      case 'equals':
        compute();
        break;
      case 'clear':
        clearAll();
        break;
      case 'delete':
        deleteLast();
        break;
    }
  });
});

关键优化点说明

  1. 状态简化:仅用3个核心变量管理计算器状态,删除所有冗余临时数组,逻辑更清晰
  2. 运算优先级实现:分两步计算,先处理乘除再处理加减,完全符合数学运算规则
  3. 连续运算支持:按下操作符时自动完成前一步运算,将结果作为新运算的起始,支持10+20+10这类连续输入
  4. 交互体验优化:阻止重复小数点输入、删除操作仅影响当前输入、分区域显示运算过程
  5. 代码结构优化:用对象统一管理运算函数,避免重复if-else判断;事件绑定用switch集中处理,可读性更强

内容的提问来源于stack exchange,提问作者kalper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 06:12:08