debugging 海森堡虫:在JavaScript中组合不同输入类型时出现意外行为

puruo6ea  于 2023-08-06  发布在  Java
关注(0)|答案(2)|浏览(97)

我目前正在做我的计算机学校项目。
如果我单独使用按钮或键盘输入,它工作得很好,但是,在混合输入的情况下会出现问题,特别是当使用Enter按钮时。
以下是我的完整项目:codepen的数据。
描述问题的最好方法是提供一个简短的示例,仅为1 + 2
可能的选项:
1.仅使用按钮,结果正确。
1.只使用按键,结果是正确的。
1.使用混合输入和=键,结果正确。
1.使用混合输入和Enter键,出现意外行为。
什么是意外行为?
1.如果第一个数字是通过按钮输入的,而第二个数字是通过键盘输入的,则显示第一个数字而不是结果。
1.如果第二个数字或两个数字都是由按钮引入的,则显示第二个数字而不是结果。
在这两种情况下,随后的Enter按下只是乘以显示的值,而不是给出错误。
1.这两个数字都是通过键盘输入的,但操作员是通过按钮输入的:程序给出正确的结果,但在冻结之后添加运算符。
下面是我如何处理一个按钮点击:

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;
}


我已经做了什么:
1.问题是这个错误不会发生在检查模式下,它在那里正常工作。
1.日志记录提供了预期值,因此没有帮助。
1.在不同的浏览器中,问题是相同的,在调试模式下它消失。

woobm2wo

woobm2wo1#

我刚刚调试完你的代码。
因此,我认为你的heisenbug是由enter键事件引起的。单击按钮时,按钮将获得焦点。然后,如果按enter键,handleKeyDown()handleButtonClick()都将连续执行。因此,您的display div首先显示正确的结果,然后重新按下的按钮,导致错误。
若要修复此错误,可以使用blur()方法从按钮移除焦点。
举例来说:

function handleButtonClick(event) {
  const buttonClicked = event.target;
  buttonClicked.blur();
  /* ... */
}

字符串

更新答案

或者,您可以使用preventDefault()方法来阻止它触发按钮上的单击事件。
举例来说:

case SYMBOLS.EQUAL:
case SYMBOLS.ENTER:
  if (!isZeroError) {
    handleEqualSign();
  }
  event.preventDefault();

mbskvtky

mbskvtky2#

只需检查handleButtonClick函数中的event.pointerType是否不是Mouse,它就可以工作。谢谢你,谢谢

相关问题