简体   繁体   中英

React: Javascript Calculator: How to return a function from a switch statement?

In a Javascript Calculator being built with React, there is a switch statement that is intended to return a function. It appears that switch statements are allowed to return if they are in a function. However, there is an error when returning the function from the switch statement: TypeError: func is not a function .

Any help would be greatly appreciated.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './style.css';


class JavascriptCalculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: 0,
      array: [],
    }
    this.display = this.display.bind(this);
    this.clear = this.clear.bind(this);
    this.calculate = this.calculate.bind(this);
  }

  calculate(){
    let regex = /[*/+‑]/;
    let text = '';
    let length = this.state.array.length;
    let operators = [];

    //console.log(this.state.array);

    // capture numbers longer than one digit by adding them to a string
    // add a comma in place of the operators so the string
    // can be split into an array.
    for (let i = 0; i < length; i++){
      if (this.state.array[i].match(/\d/)) {
        text+=this.state.array[i];
      }
      if (this.state.array[i].match(regex)){
        text+=',';
        // put the operators in their own array
        operators.push(this.state.array[i]);
      }
      if (this.state.array[i] == '='){
        break;
      }
    }

    console.log(operators);
    let numbers = text.split(',');
    console.log(numbers);
    let answer = 0;
    let func = undefined;

    // use the numbers array and the operators array
    // to calculate the answer.
    for (let i = 0; i < numbers.length; i++){

      func = returnFunc(operators.shift());
      console.log(func);
      answer = func(answer, numbers[i]);

    }

    function returnFunc(val) {
      switch (val) {
        case '+':
        return function sum(a,b) { return a+b};
        case '-':
        return function subtract(a,b) { return a-b};
        case '*':
        return function multiply(a,b) { return a*b};
        case '/':
        return function divide(a,b) {return a/b};
      }
    }
  }

  display(text){
    // if display is zero, remove the leading zero from the text.
    if(this.state.text == 0){
      this.state.text = '';
    }
    let displayed = this.state.text += text;
    this.setState({ text: displayed});

    // push the characters onto an array
    // an array is used to isolate the math operators to
    // associate them to a function
    if (text != '='){
      this.state.array.push(text);
    }

    // if text ends in equals sign, run the calculate function.
    if (text == '='){
      this.state.array.push(text);
      this.calculate();
    }
  }

  clear(id){
    this.setState({ text: id });
    this.setState({ array: [] });
    this.setState({ indices: [] });
    this.setState({ number: [] });
  }

  render() {
    return (
      <div id="javascript-calculator">
      <h1 id="title">Javascript Calculator</h1>
      <div id="display">{this.state.text}</div>
      <hr/>
      <div>
      <button id="clear" onClick={e => this.clear("0")}> clear </button>
      <button id="equals" onClick={e => this.display("=")}> = </button>
      <button id="zero" onClick={e => this.display("0")}> 0 </button>
      <button id="one" onClick={e => this.display("1")}> 1 </button>
      <button id="two" onClick={e => this.display("2")}> 2 </button>
      <button id="three" onClick={e => this.display("3")}> 3 </button>
      <button id="four" onClick={e => this.display("4")}> 4 </button>
      <button id="five" onClick={e => this.display("5")}> 5 </button>
      <button id="six" onClick={e => this.display("6")}> 6 </button>
      <button id="seven" onClick={e => this.display("7")}> 7 </button>
      <button id="eight" onClick={e => this.display("8")}> 8 </button>
      <button id="nine" onClick={e => this.display("9")}> 9 </button>
      <button id="add" onClick={e => this.display("+")}> + </button>
      <button id="subtract" onClick={e => this.display("-")}> - </button>
      <button id="multiply" onClick={e => this.display("*")}> * </button>
      <button id="divide" onClick={e => this.display("/")}> / </button>
      <button id="decimal" onClick={e => this.display(".")}> . </button>
      </div>
      </div>
    );
  }
}

ReactDOM.render(<JavascriptCalculator />, document.getElementById("app"));

index.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <title>Javascript Calculator</title>
  <style>
  </style>
</head>
<body>
  <main>
    <div id="app"></app>
    </main>
    </script>
  </body>
  </html>

You try to use an operator for every number in the input text. But usually there will be more numbers than operators, so this will fail for the last number that doesn't have an operator associated.

The returnFunc function will then be called with undefined because the operators array is empty. And will in this case also return undefined instead of a function.

You start with answer = 0 and then do the first operation. Instead, start with answer being the first number and then do the first operation with the second number and so forth

// initialize answer with first number
let answer = numbers[0];
let func = undefined;

// Start with second number 
for (let i = 1; i < numbers.length; i++){

  func = returnFunc(operators.shift());
  console.log(func);
  answer = func(answer, numbers[i]);
}

this.display(answer);

If you have a switch statement, it is always good to have a default case. If there is no other way to handle an unknown input, at least throw an exception so that you can identify that the switch is called with an invalid input.

function returnFunc(val) {
  switch (val) {
    case '+':
      // Error here because a and b are strings. 
      // Convert them to numbers first to add their values *
      return function sum(a,b) { return a+b}; 
    case '-':
      return function subtract(a,b) { return a-b};
    case '*':
      return function multiply(a,b) { return a*b};
    case '/':
      return function divide(a,b) {return a/b};
    default: // <- Use default case
      throw new Error("Called with unknown operator " + val);
  }
}

*) See How to add two strings as if they were numbers?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM