【问题标题】:Evaluating a string as a mathematical expression in JavaScript将字符串计算为 JavaScript 中的数学表达式
【发布时间】:2011-01-17 13:48:35
【问题描述】:

如何在不调用 eval(string) 来生成其数值的情况下解析和评估字符串(例如 '1+1')中的数学表达式?

在这个例子中,我希望函数接受'1+1' 并返回2

【问题讨论】:

  • 非常相似,但可能不是您要的:(Function("return 1+1;"))()

标签: javascript string math numbers


【解决方案1】:

您可以使用JavaScript Expression Evaluator library,它允许您执行以下操作:

Parser.evaluate("2 ^ x", { x: 3 });

mathjs,它允许以下内容:

math.eval('sin(45 deg) ^ 2');

我最终为我的一个项目选择了 mathjs。

【讨论】:

    【解决方案2】:

    你可以很容易地做+或-:

    function addbits(s) {
      var total = 0,
          s = s.match(/[+\-]*(\.\d+|\d+(\.\d+)?)/g) || [];
          
      while (s.length) {
        total += parseFloat(s.shift());
      }
      return total;
    }
    
    var string = '1+23+4+5-30';
    console.log(
      addbits(string)
    )

    更复杂的数学使 eval 更具吸引力——当然也更容易编写。

    【讨论】:

    • +1 - 可能比我使用的更通用,但它不适用于我的情况,因为我可能有类似 1+-2 的东西,我希望正则表达式排除无效声明也是(我认为你的允许类似“+3+4+”)
    • 我在下面发布了一个更新的答案,它使用更短的正则表达式并允许运算符之间有空格
    【解决方案3】:

    必须有人解析该字符串。如果它不是解释器(通过eval),那么它需要是你,编写一个解析例程来提取数字、运算符以及你想在数学表达式中支持的任何其他内容。

    所以,不,没有eval 就没有任何(简单的)方法。如果您担心安全性(因为您要解析的输入不是来自您控制的来源),也许您可​​以在将输入传递给eval 之前检查输入的格式(通过白名单正则表达式过滤器)?

    【讨论】:

    • 困扰我的不是安全性(我已经有一个正则表达式的工作),它更多的是浏览器的负载,因为我必须处理很多这样的字符串。自定义解析器是否可能比 eval() 更快?
    • @wheresrhys:为什么你会认为你用 JS 编写的解析器会比系统提供的解析器更快(优化,可能用 C 或 C++ 编写)?
    • eval 是迄今为止最快的方法。但是,正则表达式通常不足以确保安全性。
    • @wheresrhys:为什么你有很多这样的字符串?它们是由程序生成的吗?如果是这样,最简单的方法是在将结果转换为字符串之前计算结果。否则,就是自己编写解析器的时间了。
    【解决方案4】:

    @kennebec 出色答案的替代方法,使用更短的正则表达式并允许运算符之间有空格

    function addbits(s) {
        var total = 0;
        s = s.replace(/\s/g, '').match(/[+\-]?([0-9\.\s]+)/g) || [];
        while(s.length) total += parseFloat(s.shift());
        return total;
    }
    

    像这样使用它

    addbits('5 + 30 - 25.1 + 11');
    

    更新

    这是一个更优化的版本

    function addbits(s) {
        return (s.replace(/\s/g, '').match(/[+\-]?([0-9\.]+)/g) || [])
            .reduce(function(sum, value) {
                return parseFloat(sum) + parseFloat(value);
            });
    }
    

    【讨论】:

    • 这样就完美了,只要你只需要加减即可。这么少的代码,这么多的产品!请放心,它正在被永久使用:)
    【解决方案5】:

    简单而优雅的Function()

    function parse(str) {
      return Function(`'use strict'; return (${str})`)()
    }
    
    parse("1+2+3"); 

    【讨论】:

    • 你能解释一下它是如何工作的吗?我是这种语法的新手
    • 函数("返回 (1+2+3)")(); - 它是一个匿名函数。我们只是在执行参数(函数体)。函数("{ 返回 (1+2+3) }")();
    • ok 如何解析字符串? & 最后是什么 (${str})) -----() ` 这个括号?
    • 我看不出这比 eval 好多少。在运行此服务器端之前,请注意parse('process.exit()')
    【解决方案6】:

    我出于同样的目的创建了BigEval
    在求解表达式时,它的性能与Eval() 完全相同,并支持%、^、&、**(幂)和!等运算符。 (阶乘)。 您还可以在表达式中使用函数和常量(或者说变量)。该表达式在 PEMDAS order 中得到解决,这在包括 JavaScript 在内的编程语言中很常见。

    var Obj = new BigEval();
    var result = Obj.exec("5! + 6.6e3 * (PI + E)"); // 38795.17158152233
    var result2 = Obj.exec("sin(45 * deg)**2 + cos(pi / 4)**2"); // 1
    var result3 = Obj.exec("0 & -7 ^ -7 - 0%1 + 6%2"); //-7
    

    如果您正在处理具有任意精度的数字,也可以使用这些 Big Number 库进行算术运算。

    【讨论】:

      【解决方案7】:

      我一直在寻找用于评估数学表达式的 JavaScript 库,并找到了这两个有希望的候选者:

      • JavaScript Expression Evaluator: 更小,希望更多 轻的。允许代数表达式、替换和 功能数量。

      • mathjs:也允许复数、矩阵和单位。 专为浏览器内 JavaScript 和 Node.js 使用而构建。

      【讨论】:

      • 我现在已经测试了 JavaScript Expression Evaluator,它看起来很不错。 (mathjs 可能也很牛,但对于我的目的来说它似乎有点太大了,我也喜欢 JSEE 中的替换功能。)
      【解决方案8】:

      这是我刚才为了解决这个问题而拼凑起来的一个小函数——它通过一次分析一个字符的字符串来构建表达式(虽然它实际上非常快)。这将采用任何数学表达式(仅限于 +、-、*、/ 运算符)并返回结果。它也可以处理负值和无限数量的操作。

      剩下的唯一“要做的事情”是确保它在 + & - 之前计算 * & /。稍后会添加该功能,但现在这可以满足我的需要......

      /**
      * Evaluate a mathematical expression (as a string) and return the result
      * @param {String} expr A mathematical expression
      * @returns {Decimal} Result of the mathematical expression
      * @example
      *    // Returns -81.4600
      *    expr("10.04+9.5-1+-100");
      */ 
      function expr (expr) {
      
          var chars = expr.split("");
          var n = [], op = [], index = 0, oplast = true;
      
          n[index] = "";
      
          // Parse the expression
          for (var c = 0; c < chars.length; c++) {
      
              if (isNaN(parseInt(chars[c])) && chars[c] !== "." && !oplast) {
                  op[index] = chars[c];
                  index++;
                  n[index] = "";
                  oplast = true;
              } else {
                  n[index] += chars[c];
                  oplast = false;
              }
          }
      
          // Calculate the expression
          expr = parseFloat(n[0]);
          for (var o = 0; o < op.length; o++) {
              var num = parseFloat(n[o + 1]);
              switch (op[o]) {
                  case "+":
                      expr = expr + num;
                      break;
                  case "-":
                      expr = expr - num;
                      break;
                  case "*":
                      expr = expr * num;
                      break;
                  case "/":
                      expr = expr / num;
                      break;
              }
          }
      
          return expr;
      }
      

      【讨论】:

        【解决方案9】:

        我最近在 C# 中通过评估 Reverse Polish Notation 中的表达式(这很简单)来完成此操作(对于我们来说没有 Eval()...)。困难的部分实际上是解析字符串并将其转换为反向波兰表示法。我使用了Shunting Yard algorithm,因为维基百科和伪代码上有一个很好的例子。我发现两者都实现起来非常简单,如果您还没有找到解决方案或正在寻找替代方案,我建议您这样做。

        【讨论】:

        • 你能提供一些例子或维基百科的链接吗?
        • @LetynSOFT 伪代码可见here
        【解决方案10】:

        您可以使用 for 循环检查字符串是否包含任何无效字符,然后使用 try...catch 和 eval 来检查计算是否会引发类似 eval("2++") 的错误。

        function evaluateMath(str) {
          for (var i = 0; i < str.length; i++) {
            if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) {
              return NaN;
            }
          }
          
          
          try {
            return eval(str)
          } catch (e) {
            if (e.name !== 'SyntaxError') throw e
            return NaN;
          }
        }
        
        console.log(evaluateMath('2 + 6'))

        或者你可以设置Math.eval而不是一个函数

        Math.eval = function(str) {
          for (var i = 0; i < str.length; i++) {
            if (isNaN(str[i]) && !['+', '-', '/', '*', '%', '**'].includes(str[i])) {
              return NaN;
            }
          }
          
          
          try {
            return eval(str)
          } catch (e) {
            if (e.name !== 'SyntaxError') throw e
            return NaN;
          }
        }
        
        console.log(Math.eval('2 + 6'))

        【讨论】:

          【解决方案11】:

          我最终选择了这个解决方案,它适用于对正整数和负整数求和(对正则表达式稍作修改也适用于小数):

          function sum(string) {
            return (string.match(/^(-?\d+)(\+-?\d+)*$/)) ? string.split('+').stringSum() : NaN;
          }   
          
          Array.prototype.stringSum = function() {
              var sum = 0;
              for(var k=0, kl=this.length;k<kl;k++)
              {
                  sum += +this[k];
              }
              return sum;
          }
          

          我不确定它是否比 eval() 快,但由于我必须多次执行该操作,因此运行此脚本比创建大量 javascript 编译器实例更舒服

          【讨论】:

          • 虽然return不能在表达式中使用,sum("+1")返回NaN
          • 总是忘记 return 是否必须或不能进入三元表达式。我想排除“+1”,因为尽管它“应该”评估为一个数字,但它并不是日常意义上的数学总和的一个例子。我的代码旨在评估和过滤允许的字符串。
          【解决方案12】:

          试试nerdamer

          var result = nerdamer('12+2+PI').evaluate();
          document.getElementById('text').innerHTML = result.text();
          <script src="http://nerdamer.com/js/nerdamer.core.js"></script>
          <div id="text"></div>

          【讨论】:

            【解决方案13】:

            我相信parseIntES6 在这种情况下会有所帮助

            let func = (str) => {
              let arr = str.split("");
              return `${Number(arr[0]) + parseInt(arr[1] + Number(arr[2]))}`
            };
            
            console.log(func("1+1"));

            这里主要是parseInt用运算符解析数字。可以根据需要修改代码。

            【讨论】:

              【解决方案14】:

              试试自动计算器 https://github.com/JavscriptLab/autocalculate 使用选择器表达式计算输入值和输出

              只需为您的输出输入添加一个属性,例如 data-ac="(#firstinput+#secondinput)"

              无需任何初始化,只需添加 data-ac 属性即可。 它会自动找出动态添加的元素

              如果在输出中添加“Rs”,只需在大括号内添加 data-ac="{Rs}(#firstinput+#secondinput)"

              【讨论】:

                【解决方案15】:
                const operatorToFunction = {
                    "+": (num1, num2) => +num1 + +num2,
                    "-": (num1, num2) => +num1 - +num2,
                    "*": (num1, num2) => +num1 * +num2,
                    "/": (num1, num2) => +num1 / +num2
                }
                
                const findOperator = (str) => {
                    const [operator] = str.split("").filter((ch) => ["+", "-", "*", "/"].includes(ch))
                    return operator;
                }
                
                const executeOperation = (str) => {
                    const operationStr = str.replace(/[ ]/g, "");
                    const operator = findOperator(operationStr);
                    const [num1, num2] = operationStr.split(operator)
                    return operatorToFunction[operator](num1, num2);
                };
                
                const addition = executeOperation('1 + 1'); // ans is 2
                const subtraction = executeOperation('4 - 1'); // ans is 3
                const multiplication = executeOperation('2 * 5'); // ans is 10
                const division = executeOperation('16 / 4'); // ans is 4
                

                【讨论】:

                • 减法、乘法和除法呢?为什么要将num 乘以 1?
                • 感谢您指出@nathanfranke 我已经更新了答案以使其更通用。现在它支持所有 4 种操作。乘以 1 是将其从字符串转换为数字。我们也可以通过 +num 来实现。
                【解决方案16】:

                eval 对我来说太慢了。所以我开发了一个 StringMathEvaluator(SME),它遵循运算顺序,适用于所有包含以下内容的算术方程:

                • 整数
                • 小数
                • 数学运算符:+-*/
                • 优先括号:$operator ($expression) $operator
                • 变量:当且仅当您定义了全局和/或局部范围。
                  • 格式:[a-zA-Z][a-zA-Z0-9]*
                  • 嵌套变量运算符:$var1.$var2
                  • 函数括号:$functionId(...$commaSepArgs)
                  • 数组括号:$arrayId[index]
                • (忽略空格)

                速度测试结果:(在 chromium 浏览器中运行)

                                                                                                  却又快了(80 - 99)%,表达复杂度合理。

                                     500000 iterations (SME/eval)
                
                Integer Test '4'
                (0.346/35.646)Sec - SME 99.03% faster
                
                Simple Equation Test '4+-3'
                (0.385/35.09)Sec - SME 98.9% faster
                
                Complex Equation Test '(16 / 44 * 2) + ((4 + (4+3)-(12- 6)) / (2 * 8))'
                (2.798/38.116)Sec - SME 92.66% faster
                
                Variable Evaluation Test '2 + 5.5 + Math.round(Math.sqrt(Math.PI)) + values.one + values.two + values.four.nested'
                (6.113/38.177)Sec - SME 83.99% faster
                

                示例用法:

                初始化:

                没有变量:

                const math = new StringMathEvaluator();
                const twentyOne = math.eval('11 + 10');
                console.log('BlackJack' + twentyOne);
                // BlackJack21
                

                带变量

                const globalScope = {Math};
                const math = new StringMathEvaluator(globalScope);
                
                const localScope = {a: [[1, () => ({func: () => [17,13]})],[11,64,2]]};
                const str = '((a[0][1]().func()[0] + a[0][1]().func()[1]) * a[1][2] - Math.sqrt(a[1][1]) - a[1][0]) / a[0][0]';
                const fortyOne = math.eval(str, localScope);
                console.log('Sum' + fortyOne);
                // Sum41
                

                中小企业:

                class StringMathEvaluator {
                  constructor(globalScope) {
                    globalScope = globalScope || {};
                    const instance = this;
                    let splitter = '.';
                
                    function resolve (path, currObj, globalCheck) {
                      if (path === '') return currObj;
                      try {
                        if ((typeof path) === 'string') path = path.split(splitter);
                        for (let index = 0; index < path.length; index += 1) {
                          currObj = currObj[path[index]];
                        }
                        if (currObj === undefined && !globalCheck) throw Error('try global');
                        return currObj;
                      }  catch (e) {
                        return resolve(path, globalScope, true);
                      }
                    }
                
                    function multiplyOrDivide (values, operands) {
                      const op = operands[operands.length - 1];
                      if (op === StringMathEvaluator.multi || op === StringMathEvaluator.div) {
                        const len = values.length;
                        values[len - 2] = op(values[len - 2], values[len - 1])
                        values.pop();
                        operands.pop();
                      }
                    }
                
                    const resolveArguments = (initialChar, func) => {
                      return function (expr, index, values, operands, scope, path) {
                        if (expr[index] === initialChar) {
                          const args = [];
                          let endIndex = index += 1;
                          const terminationChar = expr[index - 1] === '(' ? ')' : ']';
                          let terminate = false;
                          let openParenCount = 0;
                          while(!terminate && endIndex < expr.length) {
                            const currChar = expr[endIndex++];
                            if (currChar === '(') openParenCount++;
                            else if (openParenCount > 0 && currChar === ')') openParenCount--;
                            else if (openParenCount === 0) {
                              if (currChar === ',') {
                                args.push(expr.substr(index, endIndex - index - 1));
                                index = endIndex;
                              } else if (openParenCount === 0 && currChar === terminationChar) {
                                args.push(expr.substr(index, endIndex++ - index - 1));
                                terminate = true;
                              }
                            }
                          }
                
                          for (let index = 0; index < args.length; index += 1) {
                            args[index] = instance.eval(args[index], scope);
                          }
                          const state = func(expr, path, scope, args, endIndex);
                          if (state) {
                            values.push(state.value);
                            return state.endIndex;
                          }
                        }
                      }
                    };
                
                    function chainedExpressions(expr, value, endIndex, path) {
                      if (expr.length === endIndex) return {value, endIndex};
                      let values = [];
                      let offsetIndex;
                      let valueIndex = 0;
                      let chained = false;
                      do {
                        const subStr = expr.substr(endIndex);
                        const offsetIndex = isolateArray(subStr, 0, values, [], value, path) ||
                                            isolateFunction(subStr, 0, values, [], value, path) ||
                                            (subStr[0] === '.' &&
                                              isolateVar(subStr, 1, values, [], value));
                        if (Number.isInteger(offsetIndex)) {
                          value = values[valueIndex];
                          endIndex += offsetIndex - 1;
                          chained = true;
                        }
                      } while (offsetIndex !== undefined);
                      return {value, endIndex};
                    }
                
                    const isolateArray = resolveArguments('[',
                      (expr, path, scope, args, endIndex) => {
                        endIndex = endIndex - 1;
                        let value = resolve(path, scope)[args[args.length - 1]];
                        return chainedExpressions(expr, value, endIndex, '');
                      });
                
                    const isolateFunction = resolveArguments('(',
                      (expr, path, scope, args, endIndex) =>
                          chainedExpressions(expr, resolve(path, scope).apply(null, args), endIndex - 1, ''));
                
                    function isolateParenthesis(expr, index, values, operands, scope) {
                      const char = expr[index];
                      if (char === '(') {
                        let openParenCount = 1;
                        let endIndex = index + 1;
                        while(openParenCount > 0 && endIndex < expr.length) {
                          const currChar = expr[endIndex++];
                          if (currChar === '(') openParenCount++;
                          if (currChar === ')') openParenCount--;
                        }
                        const len = endIndex - index - 2;
                        values.push(instance.eval(expr.substr(index + 1, len), scope));
                        multiplyOrDivide(values, operands);
                        return endIndex;
                      }
                    };
                
                    function isolateOperand (char, operands) {
                      switch (char) {
                        case '*':
                        operands.push(StringMathEvaluator.multi);
                        return true;
                        break;
                        case '/':
                        operands.push(StringMathEvaluator.div);
                        return true;
                        break;
                        case '+':
                        operands.push(StringMathEvaluator.add);
                        return true;
                        break;
                        case '-':
                        operands.push(StringMathEvaluator.sub);
                        return true;
                        break;
                      }
                      return false;
                    }
                
                    function isolateValueReg(reg, resolver, splitter) {
                      return function (expr, index, values, operands, scope) {
                        const match = expr.substr(index).match(reg);
                        let args;
                        if (match) {
                          let endIndex = index + match[0].length;
                          let value = resolver(match[0], scope);
                          if (!Number.isFinite(value)) {
                            const state = chainedExpressions(expr, scope, endIndex, match[0]);
                            if (state !== undefined) {
                              value = state.value;
                              endIndex = state.endIndex;
                            }
                          }
                          values.push(value);
                          multiplyOrDivide(values, operands);
                          return endIndex;
                        }
                      }
                    }
                    const isolateNumber = isolateValueReg(StringMathEvaluator.numReg, Number.parseFloat);
                    const isolateVar = isolateValueReg(StringMathEvaluator.varReg, resolve);
                
                
                    this.eval = function (expr, scope) {
                      scope = scope || globalScope;
                      const allowVars = (typeof scope) === 'object';
                      let operands = [];
                      let values = [];
                      let prevWasOpperand = true;
                      for (let index = 0; index < expr.length; index += 1) {
                        const char = expr[index];
                        if (prevWasOpperand) {
                          let newIndex = isolateParenthesis(expr, index, values, operands, scope) ||
                                        isolateNumber(expr, index, values, operands, scope) ||
                                        (allowVars && isolateVar(expr, index, values, operands, scope));
                          if (Number.isInteger(newIndex)) {
                            index = newIndex - 1;
                            prevWasOpperand = false;
                          }
                        } else {
                          prevWasOpperand = isolateOperand(char, operands);
                        }
                      }
                      let value = values[0];
                      for (let index = 0; index < values.length - 1; index += 1) {
                        value = operands[index](values[index], values[index + 1]);
                        values[index + 1] = value;
                      }
                      return value;
                    }
                  }
                }
                
                StringMathEvaluator.numReg = /^(-|)[0-9\.]{1,}/;
                StringMathEvaluator.varReg = /^((\.|)([a-zA-Z][a-zA-Z0-9\.]*))/;
                StringMathEvaluator.multi = (n1, n2) => n1 * n2;
                StringMathEvaluator.div = (n1, n2) => n1 / n2;
                StringMathEvaluator.add = (n1, n2) => n1 + n2;
                StringMathEvaluator.sub = (n1, n2) => n1 - n2;
                

                【讨论】:

                  【解决方案17】:

                  最好和最简单的方法是使用math.js 库。 这里有一些示例代码演示了如何使用该库。点击here 玩转。

                  // functions and constants
                  math.round(math.e, 3)                // 2.718
                  math.atan2(3, -3) / math.pi          // 0.75
                  math.log(10000, 10)                  // 4
                  math.sqrt(-4)                        // 2i
                  math.derivative('x^2 + x', 'x')      // 2*x+1
                  math.pow([[-1, 2], [3, 1]], 2)
                       // [[7, 0], [0, 7]]
                  
                  // expressions
                  math.evaluate('1.2 * (2 + 4.5)')     // 7.8
                  math.evaluate('12.7 cm to inch')     // 5 inch
                  math.evaluate('sin(45 deg) ^ 2')     // 0.5
                  math.evaluate('9 / 3 + 2i')          // 3 + 2i
                  math.evaluate('det([-1, 2; 3, 1])')  // -7
                  
                  // chaining
                  math.chain(3)
                      .add(4)
                      .multiply(2)
                      .done() // 14
                  

                  【讨论】:

                    【解决方案18】:

                    我做了一个小函数来解析一个数学表达式,包含 +,/,-,*。我使用了if 语句,我认为switch cases 会更好。 首先,我将字符串分成运算符,然后将其数字从字符串转换为浮点数,然后在执行操作时进行迭代。

                     const evaluate=(mathExpStr) => {
                        mathExpStr.replace(/[+-\/*]$/, "");
                        let regExp = /\d+/g;
                        let valueArr = (mathExpStr.match(regExp) || []).map((val) =>
                          Number.parseFloat(val)
                        );
                        let operatorArr = mathExpStr.match(/[+-\/*]/g) || [];
                        return converter(valueArr, operatorArr)
                      }
                    
                    const converter = (arr,operators)=>{
                      let arr2=[...arr]
                      for(let i=0;i<arr.length;i++){
                        let o;
                        if(arr2.length<2){return arr2[0]}
                        if(operators[i]=="+"){
                          o=arr2[0]+arr2[1]
                          arr2.splice(0, 2, o)
                          console.log(o,arr2, operators[i])
                        }
                        if(operators[i]=="-"){
                          o=arr2[0]-arr2[1]
                          arr2.splice(0,2, o)
                          console.log(o,arr2, operators[i])
                        }
                        if(operators[i]=="*"){
                          o=arr2[0]*arr2[1]
                          arr2.splice(0,2,o)
                          console.log(o,arr2, operators[i])
                        }
                        if(operators[i]=="/"){
                          o=arr2[0]/arr2[1]
                          arr2.splice(0,2, o)
                          console.log(o,arr2, operators[i])
                        }
                      }
                    }
                    // console.log(converter(valueArr, operatorArr))
                    console.log(evaluate("1+3+5+6-4*2/4"))

                    【讨论】:

                      【解决方案19】:

                      这是一个类似于 jMichael 的算法解决方案,它逐个字符地循环表达式并逐步跟踪左/运算符/右。该函数在每轮找到一个运算符字符后累积结果。此版本仅支持 '+' 和 '-' 运算符,但编写为与其他运算符一起扩展。注意:我们在循环之前将“currOp”设置为“+”,因为我们假设表达式以正浮点数开头。事实上,总的来说,我假设输入类似于来自计算器的输入。

                      function calculate(exp) {
                        const opMap = {
                          '+': (a, b) => { return parseFloat(a) + parseFloat(b) },
                          '-': (a, b) => { return parseFloat(a) - parseFloat(b) },
                        };
                        const opList = Object.keys(opMap);
                      
                        let acc = 0;
                        let next = '';
                        let currOp = '+';
                      
                        for (let char of exp) {
                          if (opList.includes(char)) {
                            acc = opMap[currOp](acc, next);
                            currOp = char;
                            next = '';
                          } else {
                            next += char;
                          } 
                        }
                      
                        return currOp === '+' ? acc + parseFloat(next) : acc - parseFloat(next);
                      }
                      

                      【讨论】:

                        【解决方案20】:

                        基于 Aniket Kudale 的 parse

                        向表达式添加上下文变量

                        function parseExpr(str: string, params: any) {
                          const names = Object.keys(params);
                          const vals = Object.values(params);
                          return Function(...names, `'use strict'; return (${str})`)(...vals);
                        }
                        

                        例子

                        > parseExpr('age > 50? x : x/2', {x: 40, age: 46})
                        20
                        
                        > parseExpr('age > 50? x : x/2', {x: 40, age: 60})
                        40
                        
                        

                        【讨论】:

                          猜你喜欢
                          • 2015-12-03
                          • 2018-05-19
                          相关资源
                          最近更新 更多