封装类似eval函数

131 阅读1分钟

在小程序的开发过程中,开发者可能会遇到需要使用动态执行代码的情况,而eval函数因其能够执行字符串中的JavaScript代码,常被视为一种解决方案。然而,在小程序的开发规范中,明确禁止使用eval函数。本文将探讨小程序不能使用eval的原因,并提供一些替代方案

export function evalMath(exp: string) {
  let express: any = exp.replace(/\s/g, "");
  let expArr: any = [];
  let symbolStack: any = [];
  let operatorNumber:string = "";//表示临时运算数
  let operator:string = "";//表示临时运算符
  for (let i = 0; i < express.length; i++) {
    if (express[i] == "(") {
      symbolStack.push(express[i]);
    }
    else if (express[i] == ")") {
      while (symbolStack[symbolStack.length - 1] != "(") {
        expArr.push(symbolStack.pop())
      }
      symbolStack.pop();

    }
    else if (isNumber(express[i])) {
      operatorNumber += express[i];
      if (i == express.length - 1) {
        expArr.push(operatorNumber);
        operatorNumber = "";
      }
      else if (express[i + 1] == ")") {
        expArr.push(operatorNumber);
        operatorNumber = "";

      }
    }
    else {
      if (operatorNumber !== "") expArr.push(operatorNumber);
      operatorNumber = "";
      operator = express[i];
      if (symbolStack.length === 0) symbolStack.push(operator);
      else if (symbolStack[symbolStack.length - 1] === "(") symbolStack.push(operator);
      else if (getOperatorPriority(operator) > getOperatorPriority(symbolStack[symbolStack.length - 1])) {
        symbolStack.push(operator);
      }
      else {
        expArr.push(symbolStack.pop())
        if (symbolStack.length == 0 || symbolStack[symbolStack.length - 1] == "(" || getOperatorPriority(operator) > getOperatorPriority(symbolStack[symbolStack.length - 1])) {
          symbolStack.push(operator);
        }
        else {
          let max = symbolStack.length - 1;
          while (getOperatorPriority(operator) <= getOperatorPriority(symbolStack[max])) {
            expArr.push(symbolStack.pop())
            if (max > 0) max--;
            else {
              symbolStack.push(operator)
              break;
            }
          }
        }
      }
      operator = "";
    }
  }
  symbolStack.reverse()
  expArr = expArr.concat(symbolStack);
  symbolStack = [];
  let numStack: any = [];
  for (let i = 0; i < expArr.length; i++) {
    if (!isOperator(expArr[i])) numStack.push(expArr[i]);
    else {
      let res = 0;
      let maxv = numStack.length - 1;
      if (expArr[i] == "+") {
        res = parseFloat(numStack[maxv - 1]) + parseFloat(numStack[maxv]);
      }
      else if (expArr[i] == "-") {
        res = parseFloat(numStack[maxv - 1]) - parseFloat(numStack[maxv]);
      }
      else if (expArr[i] == "*") {
        res = parseFloat(numStack[maxv - 1]) * parseFloat(numStack[maxv]);
      }
      else if (expArr[i] == "/") {
        res = parseFloat(numStack[maxv - 1]) / parseFloat(numStack[maxv]);
      }
      else {  //取余%
        res = parseFloat(numStack[maxv - 1]) % parseFloat(numStack[maxv]);
      }
      numStack.pop();
      numStack.pop();
      numStack.push(res);
    }
  }
  return numStack[0];
}

function getOperatorPriority(sy) {
  if (sy == "+" || sy == "-") {
    return 1;  //+,-优先级较低为1
  }
  else if (sy == "*" || sy == "/" || sy == "%") {
    return 2; //*,/优先级较高为2
  }
  else return 0; //如果不为加减乘除符号,则量化为0
}
//判断某个字符是否为数字字符的函数(包含了小数)
function isNumber(char:string):boolean {
  return /\d|\./.test(char)
}
//判断某个字符串是否为运算符
function isOperator(n) {
  let opts = ['+', '-', '*', '/', '%']
  return opts.includes(n)
}

使用

let  symbol= ['-', '+', 'right']
let x=10
let y=20
evalMath(x+symbol[0]+y) // -10