最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - "Uncaught TypeError: Cannot read properties of undefined (reading 'toString') when clickin

programmeradmin1浏览0评论

class Calculator {
  constructor(previousOperandTextElement, currentOperandTextElement) {
    this.previousOperandTextElement = previousOperandTextElement
    this.currentOperandTextElement = currentOperandTextElement
    this.clear()
  }

  clear() {
    this.previousOperandTextElement = ''
    this.currentOperandTextElement = ''
    this.operation = undefined
  }

  delete() {

  }

  appendNumber(number) {
    this.currentOperand = this.currentOperand.toString() + number.toString()
  }

  chooseOperator(operation) {

  }

  pute() {

  }

  updateDisplay() {
    this.currentOperandTextElement.innerHTML = this.currentOperand
  }


}

const numberButtons = document.querySelectorAll('[data-number]')
const operationButtons = document.querySelectorAll('[data-operation]')
const equalsButton = document.querySelector('[data-equals]')
const deleteButton = document.querySelector('[data-delete]')
const allClearButton = document.querySelector('[data-all-clear]')
const previousOperandTextElement = document.querySelector('[data-previous-operand]')
const currentOperandTextElement = document.querySelector('[data-current-operand]')

const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)

numberButtons.forEach(button => {
  button.addEventListener('click', () => {
    calculator.appendNumber(button.innerHTML)
    calculator.updateDisplay()
  })
})
*,
*::before,
*::after {
  box-sizing: border-box;
  font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
  font-weight: normal;
}

body {
  padding: 0;
  margin: 0;
  background: linear-gradient(to right, #00AAFF, #00FF6C);
}

.calculator-grid {
  display: grid;
  justify-content: center;
  align-content: center;
  min-height: 100vh;
  grid-template-columns: repeat(4, 100px);
  grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}

.calculator-grid button {
  cursor: pointer;
  font-size: 2rem;
  border: 1px solid white;
  outline: none;
  background-color: rgba(255, 255, 255, .75);
}

.calculator-grid button:hover {
  background-color: rgba(255, 255, 255, .9);
}

.span-two {
  grid-column: span 2;
}

.output {
  grid-column: 1 / -1;
  background-color: rgba(0, 0, 0, 0.75);
  border: solid 5px green;
  display: flex;
  align-items: flex-end;
  flex-direction: column;
  justify-content: space-between;
  padding: 15px;
}

.output .previous-operand {
  color: rgba(255, 255, 255, .75);
  font-size: 1.5rem;
}

.output .current-operand {
  color: rgba(255, 255, 255, .75);
  font-size: 2.5rem;
}
<!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">
  <title>Calculator</title>
  <link rel="stylesheet" href="calculator.css">
  <script src="calculator.js" defer></script>
</head>

<body>
  <div class="calculator-grid">
    <div class="output">
      <div data-previous-operand class="previous-operand"></div>
      <div data-current-operand class="current-operand"></div>
    </div>
    <button data-all-clear class="span-two">AC</button>
    <button data-delete>DEL</button>
    <button data-operation>÷</button>
    <button data-number>1</button>
    <button data-number>2</button>
    <button data-number>3</button>
    <button data-operation>*</button>
    <button data-number>4</button>
    <button data-number>5</button>
    <button data-number>6</button>
    <button data-operation>+</button>
    <button data-number>7</button>
    <button data-number>8</button>
    <button data-number>9</button>
    <button data-operation>-</button>
    <button data-number>.</button>
    <button data-number>0</button>
    <button data-equals class="span-two">=</button>
  </div>

</body>

</html>

class Calculator {
  constructor(previousOperandTextElement, currentOperandTextElement) {
    this.previousOperandTextElement = previousOperandTextElement
    this.currentOperandTextElement = currentOperandTextElement
    this.clear()
  }

  clear() {
    this.previousOperandTextElement = ''
    this.currentOperandTextElement = ''
    this.operation = undefined
  }

  delete() {

  }

  appendNumber(number) {
    this.currentOperand = this.currentOperand.toString() + number.toString()
  }

  chooseOperator(operation) {

  }

  pute() {

  }

  updateDisplay() {
    this.currentOperandTextElement.innerHTML = this.currentOperand
  }


}

const numberButtons = document.querySelectorAll('[data-number]')
const operationButtons = document.querySelectorAll('[data-operation]')
const equalsButton = document.querySelector('[data-equals]')
const deleteButton = document.querySelector('[data-delete]')
const allClearButton = document.querySelector('[data-all-clear]')
const previousOperandTextElement = document.querySelector('[data-previous-operand]')
const currentOperandTextElement = document.querySelector('[data-current-operand]')

const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)

numberButtons.forEach(button => {
  button.addEventListener('click', () => {
    calculator.appendNumber(button.innerHTML)
    calculator.updateDisplay()
  })
})
*,
*::before,
*::after {
  box-sizing: border-box;
  font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
  font-weight: normal;
}

body {
  padding: 0;
  margin: 0;
  background: linear-gradient(to right, #00AAFF, #00FF6C);
}

.calculator-grid {
  display: grid;
  justify-content: center;
  align-content: center;
  min-height: 100vh;
  grid-template-columns: repeat(4, 100px);
  grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}

.calculator-grid button {
  cursor: pointer;
  font-size: 2rem;
  border: 1px solid white;
  outline: none;
  background-color: rgba(255, 255, 255, .75);
}

.calculator-grid button:hover {
  background-color: rgba(255, 255, 255, .9);
}

.span-two {
  grid-column: span 2;
}

.output {
  grid-column: 1 / -1;
  background-color: rgba(0, 0, 0, 0.75);
  border: solid 5px green;
  display: flex;
  align-items: flex-end;
  flex-direction: column;
  justify-content: space-between;
  padding: 15px;
}

.output .previous-operand {
  color: rgba(255, 255, 255, .75);
  font-size: 1.5rem;
}

.output .current-operand {
  color: rgba(255, 255, 255, .75);
  font-size: 2.5rem;
}
<!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">
  <title>Calculator</title>
  <link rel="stylesheet" href="calculator.css">
  <script src="calculator.js" defer></script>
</head>

<body>
  <div class="calculator-grid">
    <div class="output">
      <div data-previous-operand class="previous-operand"></div>
      <div data-current-operand class="current-operand"></div>
    </div>
    <button data-all-clear class="span-two">AC</button>
    <button data-delete>DEL</button>
    <button data-operation>÷</button>
    <button data-number>1</button>
    <button data-number>2</button>
    <button data-number>3</button>
    <button data-operation>*</button>
    <button data-number>4</button>
    <button data-number>5</button>
    <button data-number>6</button>
    <button data-operation>+</button>
    <button data-number>7</button>
    <button data-number>8</button>
    <button data-number>9</button>
    <button data-operation>-</button>
    <button data-number>.</button>
    <button data-number>0</button>
    <button data-equals class="span-two">=</button>
  </div>

</body>

</html>

Share Improve this question edited Sep 4, 2021 at 5:57 mplungjan 179k28 gold badges182 silver badges240 bronze badges asked Sep 4, 2021 at 5:54 kidDeleteskidDeletes 231 gold badge1 silver badge5 bronze badges 1
  • Uncaught TypeError: Cannot read properties of undefined (reading 'toString') at Calculator.appendNumber (calculator.js:22) at HTMLButtonElement.<anonymous> (calculator.js:55) – kidDeletes Commented Sep 4, 2021 at 5:55
Add a ment  | 

3 Answers 3

Reset to default 0

You do not HAVE this.currentOperandTextElement since it is defined outside the class

updateDisplay() { 
  currentOperandTextElement.innerHTML = this.currentOperand
}

Also I changed to delegation

document.querySelector('.calculator-grid').addEventListener('click', (e) => {
  const tgt = e.target;
  if (tgt.classList.contains('number')) {
    calculator.appendNumber(tgt.textContent)
    calculator.updateDisplay()
  }
})

All textContents are string so no need for number.toString

Lastly I do not remend using data attributes as a placeholder

This makes more sense

<button id="all-clear" class="span-two">AC</button>
<button id="delete">DEL</button>
<button class="operation">÷</button>
<button class="number">1</button>
<button class="number">2</button>
<button class="number">3</button>
<button class="operation">*</button>
<button class="number">4</button>
<button class="number">5</button>
<button class="number">6</button>
<button class="operation">+</button>
<button class="number">7</button>
<button class="number">8</button>
<button class="number">9</button>
<button class="operation">-</button>
<button class="number">.</button>
<button class="number">0</button>
<button id="equals" class="operation span-two">=</button>

class Calculator {
  constructor(previousOperandTextElement, currentOperandTextElement) {
    this.previousOperandTextElement = previousOperandTextElement
    this.currentOperandTextElement = currentOperandTextElement
    this.currentOperand = ""
    this.clear()
  }

  clear() {
    this.previousOperandTextElement = ''
    this.currentOperandTextElement = ''
    this.operation = undefined
  }

  delete() {

  }

  appendNumber(number) {
    this.currentOperand  += number
  }

  chooseOperator(operation) {

  }

  pute() {

  }

  updateDisplay() { 
    currentOperandTextElement.innerHTML = this.currentOperand
  }


}

const equalsButton = document.getElementById('equals')
const deleteButton = document.getElementById('delete')
const allClearButton = document.getElementById('all-clear')
const previousOperandTextElement = document.querySelector('[data-previous-operand]')
const currentOperandTextElement = document.querySelector('[data-current-operand]')

const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)

document.querySelector('.calculator-grid').addEventListener('click', (e) => {
  const tgt = e.target;
  if (tgt.classList.contains('number')) {
    calculator.appendNumber(tgt.textContent)
    calculator.updateDisplay()
  }
})
*,
*::before,
*::after {
  box-sizing: border-box;
  font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
  font-weight: normal;
}

body {
  padding: 0;
  margin: 0;
  background: linear-gradient(to right, #00AAFF, #00FF6C);
}

.calculator-grid {
  display: grid;
  justify-content: center;
  align-content: center;
  min-height: 100vh;
  grid-template-columns: repeat(4, 100px);
  grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}

.calculator-grid button {
  cursor: pointer;
  font-size: 2rem;
  border: 1px solid white;
  outline: none;
  background-color: rgba(255, 255, 255, .75);
}

.calculator-grid button:hover {
  background-color: rgba(255, 255, 255, .9);
}

.span-two {
  grid-column: span 2;
}

.output {
  grid-column: 1 / -1;
  background-color: rgba(0, 0, 0, 0.75);
  border: solid 5px green;
  display: flex;
  align-items: flex-end;
  flex-direction: column;
  justify-content: space-between;
  padding: 15px;
}

.output .previous-operand {
  color: rgba(255, 255, 255, .75);
  font-size: 1.5rem;
}

.output .current-operand {
  color: rgba(255, 255, 255, .75);
  font-size: 2.5rem;
}
<!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">
  <title>Calculator</title>
  <link rel="stylesheet" href="calculator.css">
  <script src="calculator.js" defer></script>
</head>

<body>
  <div class="calculator-grid">
    <div class="output">
      <div data-previous-operand class="previous-operand"></div>
      <div data-current-operand class="current-operand"></div>
    </div>
    <button id="all-clear" class="span-two">AC</button>
    <button id="delete">DEL</button>
    <button class="operation">÷</button>
    <button class="number">1</button>
    <button class="number">2</button>
    <button class="number">3</button>
    <button class="operation">*</button>
    <button class="number">4</button>
    <button class="number">5</button>
    <button class="number">6</button>
    <button class="operation">+</button>
    <button class="number">7</button>
    <button class="number">8</button>
    <button class="number">9</button>
    <button class="operation">-</button>
    <button class="number">.</button>
    <button class="number">0</button>
    <button id="equals" class="operation span-two">=</button>
  </div>

</body>

</html>

The currentOperand variable you use in the Calculator.appendNumber method is not defined.

You should use the Null Coalescing Operator (??) to provide a value if the first argument is undefined or null.

The passed argument number will always be a string, so there isn't a need to call the toString method on it again.

appendNumber(number) {
    this.currentOpend = (this.currentOperand ?? '') + number;
}

or set the value of the this.currentOperand in the constructor, then you won't need to use the ?? operator

constructor(previousOperandTextElement, currentOperandTextElement) {
    ...
    this.currentOperand = '';
}

and your Calculator.clear method should be

clear() {
    this.previousOperandTextElement.innerText = '';
    this.currentOperandTextElement.innerText = '';
    this.operation = undefined;
}

Change this code

appendNumber(number) {
this.currentOperand = this.currentOperand.toString() + number.toString()

}

to

appendNumber(number){
    this.currentOperand = (this.currentOperand ? this.currentOperand.toString() : ' ')  + number.toString();

}

it worked for me. Try this code once.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论