JavaScript 在页面上给出 NaN 错误,但变量实际上是一个数字

JavaScript gives NaN error on the page but variable is actually a number

我正在尝试用 JS 制作一个基本的计算器。它正在迈出第一步。我的意思是它计算 1+3 = 4 但它不能计算 4+2 例如。实际上它是在控制台上计算的,但我无法在网页上显示它,所以DOM。那么你知道为什么会这样吗?

const operations = {
    '+': (a, b) => a + b,
    '-': (a, b) => a - b,
    '*': (a, b) => a * b,
    '/': (a, b) => a / b
}

const doOpr = function (sign) {
    labelUser.value += `${sign}`

    // const deleteFn = function () {
    //     labelUser.value = labelUser.value.slice(0, labelUser.value.length - 1)
    // }
    // btnDelete.addEventListener('click', deleteFn)

    const equalFn = function (sign) {
        let numbers = labelUser.value.split(`${sign}`)
        //console.log(numbers)
        const operation = operations[`${sign}`]
        let result = operation(+numbers[0], +numbers[1])
        labelUser.value = result

        //console.log(typeof result, numbers) //This line proves that result is a number. Not a NaN. 
        //Also it proves numbers array contains only two elements.

        return
    }
    btnEqual.addEventListener('click', equalFn.bind(null, sign))
}

btnPlus.addEventListener('click', doOpr.bind(null, '+'))

btnExtr.addEventListener('click', doOpr.bind(null, '-'))

const btnPlus = document.querySelector('.btn-plus')
const btnExtr = document.querySelector('.btn-extr')
const btnEqual = document.querySelector('.btn-equal')
const btnDelete = document.querySelector('.btn-delete')
const labelUser = document.querySelector('.user__input')
const form = document.querySelector('.user__form')

form.reset()
const operations = {
    '+': (a, b) => a + b,
    '-': (a, b) => a - b,
    '*': (a, b) => a * b,
    '/': (a, b) => a / b
}

const doOpr = function (sign) {
    labelUser.value += `${sign}`

    // const deleteFn = function () {
    //     labelUser.value = labelUser.value.slice(0, labelUser.value.length - 1)
    // }
    // btnDelete.addEventListener('click', deleteFn)

    const equalFn = function (sign) {
        let numbers = labelUser.value.split(`${sign}`)
        const operation = operations[`${sign}`]
        let result = operation(+numbers[0], +numbers[1])
        labelUser.value = result
        console.log(typeof result, numbers)
        return
    }
    btnEqual.addEventListener('click', equalFn.bind(null, sign))
}

btnPlus.addEventListener('click', doOpr.bind(null, '+'))

btnExtr.addEventListener('click', doOpr.bind(null, '-'))
*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  box-sizing: inherit;
}

html {
  font-size: 62.5%;
  box-sizing: border-box;
}

.container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 25%;
  height: 85%;
  background-color: olive;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(6, 1fr);
}

.user__form {
  grid-row: 1/3;
  grid-column: 1/-1;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.user__input {
  width: 90%;
  height: 80%;
  font-size: 6rem;
  text-align: right;
  padding: 0 3rem;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Basic Calculator</title>
    <link rel="stylesheet" href="./css/style.css">
</head>

<body>
    <div class="container">
        <form class="user__form">
            <input type="text" class="user__input" placeholder="Entry num">
        </form>

        <button class="btn-plus">
            addition
        </button>

        <button class="btn-extr">
            extraction
        </button>

        <button class="btn-equal">
            equal
        </button>

        <button class="btn-delete">
            delete
        </button>

    </div>
    <script src="./script.js"></script>
</body>

</html>

这里可以看到,我先输入2+1,然后计算显示出来,然后我再试同样的操作,计算出来了,但是页面上显示不出来。

如果您执行以下操作,就会出现当前问题:

  1. 输入“2”。
  2. 按“添加”按钮。
  3. 输入“3”。
  4. 按“等于”按钮。
  5. 按“添加”按钮。
  6. 键入“4”。
  7. 按“等于”按钮。

第 2 步将向等号按钮添加一个事件侦听器,并在单击时(第 4 步)执行添加逻辑。但是,听众仍然存在。在第 5 步,添加了另一个侦听器。在第 7 步,两个事件侦听器触发:第一个将执行加法 (5 + 4 = 9),第二个将尝试通过拆分 + 并对两个值求和来再次执行加法。但是,该值已经只是“9”,所以这会导致问题,因为没有两个操作数:

const operations = {
    '+': (a, b) => a + b,
}

const value = "9";

const numbers = value.split("+");
const a = +numbers[0];
const b = +numbers[1];

console.log(numbers, a, b);

console.log(operations["+"](a, b))

由于问题是多个事件侦听器,您可以制作一个在触发后自毁的事件侦听器:

const btnPlus = document.querySelector('.btn-plus')
const btnExtr = document.querySelector('.btn-extr')
const btnEqual = document.querySelector('.btn-equal')
const btnDelete = document.querySelector('.btn-delete')
const labelUser = document.querySelector('.user__input')
const form = document.querySelector('.user__form')

form.reset()
const operations = {
    '+': (a, b) => a + b,
    '-': (a, b) => a - b,
    '*': (a, b) => a * b,
    '/': (a, b) => a / b
}

const doOpr = function (sign) {
    labelUser.value += `${sign}`

    const equalFn = function(sign) { //equalFN should return a function 
      return function equal() { //give the function a name --+
        let numbers = labelUser.value.split(`${sign}`) //    |
        const operation = operations[`${sign}`] //           |
        let result = operation(+numbers[0], +numbers[1]) //  |
        console.log(typeof result, result, numbers) //       |
        labelUser.value = result //                          |
        btnEqual.removeEventListener("click", equal); //<----+ use the name to remove it
        return
      }
    }
    btnEqual.addEventListener('click', equalFn(sign))
}


btnPlus.addEventListener('click', doOpr.bind(null, '+'))

btnExtr.addEventListener('click', doOpr.bind(null, '-'))
*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  box-sizing: inherit;
}

html {
  font-size: 62.5%;
  box-sizing: border-box;
}

.container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 25%;
  height: 85%;
  background-color: olive;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(6, 1fr);
}

.user__form {
  grid-row: 1/3;
  grid-column: 1/-1;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.user__input {
  width: 90%;
  height: 80%;
  font-size: 6rem;
  text-align: right;
  padding: 0 3rem;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Basic Calculator</title>
    <link rel="stylesheet" href="./css/style.css">
</head>

<body>
    <div class="container">
        <form class="user__form">
            <input type="text" class="user__input" placeholder="Entry num">
        </form>

        <button class="btn-plus">
            addition
        </button>

        <button class="btn-extr">
            extraction
        </button>

        <button class="btn-equal">
            equal
        </button>

        <button class="btn-delete">
            delete
        </button>

    </div>
    <script src="./script.js"></script>
</body>

</html>

但是,拥有一次性事件侦听器通常不是一个好主意。这意味着正确的操作取决于操作的顺序。事实上,现在无法输入“2+3”并计算它,您必须按“加法”按钮来注册加法处理程序。

相反,这可以解耦。如果您只需要一个运算符,那么通过非常小的修改,您可以使 equals 处理程序只检查 operations 中定义的操作数。如果你有,那就用正常的逻辑对输入进行拆分处理。

这使您可以单独进行相等操作,而不是在评估结果之前依赖于单击“加法”或“减法”。因此,这两个按钮变得非常简单,只是在输入字段中添加一个“+”或“-”。但是,仅使用键盘输入“2+3”的用户也可以工作,并将被评估为 5。

const btnPlus = document.querySelector('.btn-plus')
const btnExtr = document.querySelector('.btn-extr')
const btnEqual = document.querySelector('.btn-equal')
const btnDelete = document.querySelector('.btn-delete')
const labelUser = document.querySelector('.user__input')
const form = document.querySelector('.user__form')

form.reset()
const operations = {
    '+': (a, b) => a + b,
    '-': (a, b) => a - b,
    '*': (a, b) => a * b,
    '/': (a, b) => a / b
}

const doOpr = function (sign) {
    labelUser.value += `${sign}`
}

//extract equalFn as a separate handler
const equalFn = function () {
    let sign;
    //search the user input for any supported operation
    //and set the sign to that operation
    for (const op of Object.keys(operations)) {
      if (labelUser.value.includes(op)) {
          sign = op;
          break;
        }
    }
    if (sign === undefined)
      return; //cannot be calculated
    
    //use the previous logic to split the input and process it
    let numbers = labelUser.value.split(sign)
    const operation = operations[sign]
    let result = operation(+numbers[0], +numbers[1])
    console.log(typeof result, result, numbers)
    labelUser.value = result
    return
}

btnPlus.addEventListener('click', doOpr.bind(null, '+'))
btnExtr.addEventListener('click', doOpr.bind(null, '-'))

//only add equalFn a single time as a handler
btnEqual.addEventListener('click', equalFn)
*,
*::after,
*::before {
  margin: 0;
  padding: 0;
  box-sizing: inherit;
}

html {
  font-size: 62.5%;
  box-sizing: border-box;
}

.container {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 25%;
  height: 85%;
  background-color: olive;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(6, 1fr);
}

.user__form {
  grid-row: 1/3;
  grid-column: 1/-1;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.user__input {
  width: 90%;
  height: 80%;
  font-size: 6rem;
  text-align: right;
  padding: 0 3rem;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Basic Calculator</title>
    <link rel="stylesheet" href="./css/style.css">
</head>

<body>
    <div class="container">
        <form class="user__form">
            <input type="text" class="user__input" placeholder="Entry num">
        </form>

        <button class="btn-plus">
            addition
        </button>

        <button class="btn-extr">
            extraction
        </button>

        <button class="btn-equal">
            equal
        </button>

        <button class="btn-delete">
            delete
        </button>

    </div>
    <script src="./script.js"></script>
</body>

</html>