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

求助:实现计算器多步连续运算功能|The Odin Project 练习

计算器多步运算实现与优先级问题解答

我正在完成The Odin Project的计算器练习,基础功能已接近完成(仅少量bug),但不知如何实现最后一项多步运算功能。

练习要求:

用户可连续执行多个运算,每次仅计算一对数字。例如12 + 7 - 5 * 3 = 应得出42。
计算器每次仅计算一对数字:如按下12、+、7、-,需先计算12+7得19并显示,再将19作为新计算的首个数字搭配-继续运算。

目前我的计算器无法实现该功能,同时疑惑是否需处理乘除优先于加减的优先级,恳请指点。


我的代码

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <script src="main.js" defer></script>
    <title>Calculator</title>
</head>
<body>
    <div class="calcContainer">
        <div class="output-clear-container">
            <div class="output">
                <div class="prev-result"></div>
                <div class="current-result">0</div>
            </div>
            <button class="clear">AC</button>
        </div>
            <div class="par">
                <button class="number">7</button>
                <button class="number">8</button>
                <button class="number">9</button>
                <button class="operator clr">÷</button>
            </div>
            <div class="par">
                <button class="number">4</button>
                <button class="number">5</button>
                <button class="number">6</button>
                <button class="operator clr">x</button>
            </div>
            <div class="par">
                <button class="number">1</button>
                <button class="number">2</button>
                <button class="number">3</button>
                <button class="operator clr">-</button>
            </div>
            <div class="par">
                <button class="decimal clr">.</button>
                <button class="number">0</button>
                <button class="equal clr">=</button>
                <button class="operator clr">+</button>
            </div>
    </div>
</body>
</html>

CSS

body {
    width: 100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
}

.calcContainer {
    background: linear-gradient(276deg, #40a179, #77cea9);
    padding: 1em;
    border-radius: 5px;
    border: 1px solid #000;
}

button {
    padding: 1em;
    margin: 0.1em;
    width: 40px;
    background: #a2ffaf;
    border: 1px solid #fff;
    border-radius: 3px;
    cursor: pointer;
}

button:hover {
    background: #72e782;
}

.clr {
    background: #87e4bd;
}

.clr:hover {
    background: #53ad88;
}

.clear {
    margin: 0em 0.1em 0.5em 0.5em;
    padding: 0;
}

.output-clear-container {
    display: flex;
}

.output {
    flex-grow: 1;
    height: 40px;
    background: #c2fcca;
    border-radius: 5px;
    border: 1px solid #fff;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: flex-end;
    padding-right: 0.5em;
    margin-bottom: 0.5em;
}

.par {
    margin-bottom: 0.3em;
}

.prev-result {
    font-size: 14px;
    padding-bottom: 0.3em;
    color:#40a179;
}

.current-result {
    font-size: 18px;
}

JavaScript

const displayPrevResult = document.querySelector('.prev-result');
const displayCurrentResult = document.querySelector('.current-result');
const equal = document.querySelector('.equal');
const decimal = document.querySelector('.decimal');
const clear = document.querySelector('.clear');

const numberBtn = document.querySelectorAll('.number');
const operatorBtn = document.querySelectorAll('.operator');
let current = '';
let previous = '';
let opString = '';


numberBtn.forEach((button) => {
    button.addEventListener('click', (e) => {
        getNum(e.target.textContent);
    })
})

operatorBtn.forEach((button) => {
    button.addEventListener('click', (e) => {
        getOp(e.target.textContent);
    })
})


clear.addEventListener('click', clearCalc);


// Operate when clicking equal
equal.addEventListener('click', () => {
    current = parseFloat(current);
    previous = parseFloat(previous);

    if (opString === '+') {
        current = add(previous, current);
    } else if (opString === '-') {
        current = subtract(previous, current);
    } else if (opString === 'x') {
        current = multiply(previous, current);
    } else if (opString === '÷') {
        if (current === 0) {
            clearCalc();
            displayCurrentResult.textContent = 'ERROR';
            return;
        }
        current = divide(previous, current);
    }

    displayCurrentResult.textContent = current;
})

function clearCalc() {
    current = '';
    previous = '';
    displayCurrentResult.textContent = '0';
    displayPrevResult.textContent = '';
}


// Store current number, get operator and display it
function getOp(opStr) {
    opString = opStr;
    previous = current;
    displayPrevResult.textContent = previous;
    current = '';
}


// Get the number and display it
function getNum(num) {
    current += num;
    displayCurrentResult.textContent = current;
}



// Operating functions
function add(a, b) {
    return a + b;
}

function subtract(a, b) {
    return a - b;
}

function multiply(a, b) {
    return a * b;
}

function divide(a, b) {
    return a / b;
}

function operate(a, b) {
    return divide(b, a);
}

console.log(operate(22, 4));

问题解答

一、多步运算功能实现

当前代码仅在点击=时执行计算,要实现连续运算,需在点击下一个运算符时就完成上一次的计算,修改getOp函数并优化equal点击逻辑:

  1. 修改getOp函数:
function getOp(opStr) {
    // 已有运算数据时,先完成上一次计算
    if (previous !== '' && current !== '') {
        current = parseFloat(current);
        previous = parseFloat(previous);

        if (opString === '+') {
            current = add(previous, current);
        } else if (opString === '-') {
            current = subtract(previous, current);
        } else if (opString === 'x') {
            current = multiply(previous, current);
        } else if (opString === '÷') {
            if (current === 0) {
                clearCalc();
                displayCurrentResult.textContent = 'ERROR';
                opString = opStr;
                previous = '';
                current = '';
                return;
            }
            current = divide(previous, current);
        }
        // 更新显示与状态
        displayCurrentResult.textContent = current;
        previous = current.toString();
        current = '';
    }
    // 记录新运算符
    opString = opStr;
    // 首次点击运算符时赋值previous
    if (previous === '') {
        previous = current;
        displayPrevResult.textContent = previous;
        current = '';
    } else {
        displayPrevResult.textContent = `${previous} ${opString}`;
    }
}
  1. 优化equal点击事件:
equal.addEventListener('click', () => {
    if (previous === '' || current === '') return; // 避免空值计算
    current = parseFloat(current);
    previous = parseFloat(previous);

    if (opString === '+') {
        current = add(previous, current);
    } else if (opString === '-') {
        current = subtract(previous, current);
    } else if (opString === 'x') {
        current = multiply(previous, current);
    } else if (opString === '÷') {
        if (current === 0) {
            clearCalc();
            displayCurrentResult.textContent = 'ERROR';
            return;
        }
        current = divide(previous, current);
    }

    displayCurrentResult.textContent = current;
    // 将结果设为previous,支持后续继续运算
    previous = current.toString();
    opString = '';
    displayPrevResult.textContent = '';
})

二、运算优先级处理

根据练习要求,计算器需要按输入顺序依次计算每一对数字,不需要处理乘除优先于加减的优先级。示例12 +7 -5 *3会按以下步骤计算:

  1. 12+7=19
  2. 19-5=14
    3.14*3=42

如果后续要实现符合数学优先级的计算器,可使用后缀表达式(逆波兰表达式)或递归解析,但这超出了当前练习的要求。

三、额外小优化

添加小数输入限制(避免多次输入小数点):

decimal.addEventListener('click', () => {
    if (!current.includes('.')) {
        current += '.';
        displayCurrentResult.textContent = current;
    }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 07:33:53