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

JavaScript计算器混合输入(Enter键)引发Heisenbug问题求助

计算器混合输入(Enter键触发)异常问题

我正在开发一个学校计算器项目,单独使用按钮或键盘输入时功能正常,但混合输入(尤其是按下Enter键)时出现异常。

以计算1 + 2为例:

  • 仅用按钮输入:结果正确
  • 仅用键盘输入:结果正确
  • 混合输入并按=键:结果正确
  • 混合输入并按Enter键:出现异常

异常表现

  • 第一个数用按钮输入,第二个数用键盘输入:显示第一个数而非结果
  • 第二个数或两个数用按钮输入:显示第二个数而非结果;后续按Enter键会将显示值相乘而非报错
  • 两个数用键盘输入,运算符用按钮输入:结果正确但会追加运算符并冻结

相关处理函数

按钮点击处理函数

function handleButtonClick(event) {
    const buttonClicked = event.target;

    hideErrorIfEqualErrorDisplayed('mouse', buttonClicked);

    switch (buttonClicked) {
        case buttonDecimalPoint:
            handleDecimalPointButton();
            break;
        case buttonClear:
            clearAll();
            break;
        case buttonDelete:
            deleteLastSymbol();
            break;
        case buttonEqual:
            handleEqualSign();
            break;
        default:
            const classButton = buttonClicked.classList;
            const valueOfClickedButton = buttonClicked.textContent;

            if (classButton.contains('button-digit')) {
                handleDigitButton(valueOfClickedButton);
            } else if (classButton.contains('button-operator')) {
                handleOperatorButton(valueOfClickedButton);
            }
            break;
    }
}

键盘输入处理函数

function handleKeyDown(event) {
    const keyPressed = event.key;

    hideErrorIfEqualErrorDisplayed('keyboard', keyPressed);

    switch (keyPressed) {
        case SYMBOLS.DOT:
          if (isDecimalPointDisabled) {
            event.preventDefault();
          } else {
            handleDecimalPointButton();
          }
          break;
    
        case SYMBOLS.BACKSPACE:
          deleteLastSymbol();
          break;
    
        case SYMBOLS.ESCAPE:
          clearAll();
          break;
    
        case SYMBOLS.EQUAL:
        case SYMBOLS.ENTER:
            console.log(keyPressed);
          if (isZeroError) {
            event.preventDefault();
          } else {
            console.log(`current display: ${containerDisplay.textContent}`);
            console.log('Go to handleEqualSign()');
            handleEqualSign();
          }
          console.log('break');
          break;
    
        default:
          if (checkIfDigit(keyPressed)) {
            handleDigitButton(keyPressed);
          } else if (Object.values(OPERATORS).includes(keyPressed)) {
            if (areOperatorsDisabled) {
              event.preventDefault();
            } else {
              handleOperatorButton(keyPressed);
            }
          } else {
            event.preventDefault();
          }
          break;
      }
}

其他相关函数

function handleEqualSign(){
    if (!isSecondNumber) {
        showErrorMessage(errorEqual);
        return;
    }

    console.log('Go to getResult()');
    getResult();
}

function hideErrorIfEqualErrorDisplayed(inputSource, symbolTyped) { // inputSource: keyboard or mouse
    if (isEqualError) {
        if (inputSource === 'mouse' && symbolTyped !== buttonEqual) {
            hideErrorMessage(errorEqual);
        } else if (inputSource === 'keyboard' && symbolTyped !== SYMBOLS.ENTER && symbolTyped !== SYMBOLS.EQUAL) {
            hideErrorMessage(errorEqual);
        }
    }
}

function handleOperatorButton(operatorValue) {
    disableButton(buttonDecimalPoint);

    if (isOperator) { // Display and use the last operator if the user has clicked more than one in a row
        deleteLastSymbol();
    }

    if (!isSecondNumber) {
        shiftFromFirstToOperator();   
    } else {
        getResult(isAfterEqualClick=false);
    }

    addToDisplay(operatorValue, gap=true)

    operator = operatorValue;  
}

function getResult(isAfterEqualClick=true) {  // isAfterEqualClick = true when we enter the function after the clicking '=' or pressing the 'Enter' key, false after clicking any other operator.
    const result = operate(parseFloat(number1), parseFloat(number2), operator);
    console.log(`getResult() arguments: ${parseFloat(number1)}, ${parseFloat(number2)}, ${operator} `);
    console.log(`Result: ${result}`);

    containerDisplay.textContent = parseFloat(result.toFixed(5));
    console.log(`containerDisplay.textContent: ${containerDisplay.textContent }`);
    
    number1 = result.toString();
    isResult = true;
    number2 = EMPTY; 
    isSecondNumber = false;

    if (isAfterEqualClick) {
        console.log('isAfterEqualClick = True');
        isFirstNumber = true;
        isOperator = false;
        operator = EMPTY;
    } else {
        console.log('isAfterEqualClick = False');
        shiftFromFirstToOperator();
    }

    if (!Number.isInteger(result)) {
        disableButton(buttonDecimalPoint);
    } else {
        enableDecimalPointIfDisabled();
    } 
}

function handleDigitButton(digitValue) { 
    if (isFirstNumber) { 
        handleFirstNumber(digitValue);
    } else if (isOperator && !isSecondNumber) { 
        handleStartOfSecondNumber(digitValue);
    } else {  
        handleContinueOfSecondNumber(digitValue);
    }
} 

function add(addend1, addend2) {
    return addend1 + addend2;
}

已排查情况

  • 该Bug在检查模式下不出现,功能正常
  • 日志输出符合预期,无法定位问题
  • 不同浏览器均存在该问题,调试模式下问题消失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 00:42:37