javascriptcalculatorclass-constructors

How could I re-write this code without the Calculator constructor?


I am making a calculator for a 12 week bootcamp and the MVP states we are not to use constructors.

Below is all the functions within the constructor. I need all of the functions to continue to work, I just need them NOT inside a constructor to meet the requirements of my MVP.

I understand conceptually how to make a calculator, and have opted to comb through and rewrite vanilla JS with notes throughout to solidify my understanding.

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

  clear() {
    this.currentOperand = ''
    this.previousOperand = ''
    this.operation = undefined
  }

  delete() {
    this.currentOperand = this.currentOperand.toString().slice(0, -1)
  }

  appendNumber(number) {
    if (number === '.' && this.currentOperand.includes('.')) return
    this.currentOperand = this.currentOperand.toString() + number.toString()
  }

  chooseOperation(operation) {
    if (this.currentOperand === '') return
    if (this.previousOperand !== '') {
      this.compute()
    }
    this.operation = operation
    this.previousOperand = this.currentOperand
    this.currentOperand = ''
  }

  compute() {
    let computation
    const prev = parseFloat(this.previousOperand)
    const current = parseFloat(this.currentOperand)
    if (isNaN(prev) || isNaN(current)) return
    switch (this.operation) {
      case '+':
        computation = prev + current
        break
      case '-':
        computation = prev - current
        break
      case '*':
        computation = prev * current
        break
      case '÷':
        computation = prev / current
        break
      default:
        return
    }
    this.currentOperand = computation
    this.operation = undefined
    this.previousOperand = ''
  }

  getDisplayNumber(number) {
    const stringNumber = number.toString()
    const integerDigits = parseFloat(stringNumber.split('.')[0])
    const decimalDigits = stringNumber.split('.')[1]
    let integerDisplay
    if (isNaN(integerDigits)) {
      integerDisplay = ''
    } else {
      integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 })
    }
    if (decimalDigits != null) {
      return `${integerDisplay}.${decimalDigits}`
    } else {
      return integerDisplay
    }
  }

  updateDisplay() {
    this.currentOperandTextElement.innerText =
      this.getDisplayNumber(this.currentOperand)
    if (this.operation != null) {
      this.previousOperandTextElement.innerText =
        `${this.getDisplayNumber(this.previousOperand)} ${this.operation}`
    } else {
      this.previousOperandTextElement.innerText = ''
    }
  }
}

Solution

  • First a comment: the parameters to the constructor are useless, as the constructor assigns new values immediately by its call to clear.

    Without prototype (class instance) functions, you could give every function a parameter that represents the state of the calculator. Or, if you would have used this class to create one instance only, you could make that state global, which is what may be the suggested approach in a beginner's course.

    In the latter case (globals), define each current this property as global variable, like this:

    var previousOperandTextElement = "", 
        currentOperandTextElement = "",
        operation;
    

    And then:

    Like so:

    var previousOperandTextElement = "", 
        currentOperandTextElement = "",
        operation;
    
    clear();
    
    function clear() {
        currentOperand = ''
        previousOperand = ''
        operation = undefined
    }
    
    function delete() {
        currentOperand = currentOperand.toString().slice(0, -1)
    }
    
    function appendNumber(number) {
        if (number === '.' && currentOperand.includes('.')) return
        currentOperand = currentOperand.toString() + number.toString()
    }
    
    // ...etc ...etc