当前位置: 首页 > 工具软件 > eval5 > 使用案例 >

关于eval在微信小程序中无法使用的问题

程修雅
2023-12-01

引言

JavaScript中的eval函数是颇受开发者争议的问题之一,问题主要在于其可能导致的不安全性,因此它也遭到了微信官方的封禁。记得以前有些人想用eval实现热更新代码,而不用经过审核,封掉这类型的代码是正常的。但是,eval函数的优点也是很明显的。例如,使用JS编写一个计算器程序,在遇到"2+1-3*5"这样的字符串时,使用eval就可以很容易地计算出,类似如:

var result="2+1-3*5";
console.log(eval(result));

那我们是否就真的要和eval说再见了呢,不是的,下面有几种解决方案可以替代eval。

一、eval5

eval5是基于 TypeScript 编写的 JavaScript 解释器,支持完整 ES5 语法支持浏览器、node.js、小程序等 JavaScript 运行环境
可用于:

  1. 浏览器环境中需要使用沙盒环境执行 JavaScript 脚本
  2. 控制执行时长
  3. 不支持eval Function的 JavaScript 运行环境:如 微信小程序 demo we-script taro-script

我们可以通过npm安装:

npm install --save eval5

基本使用方法也很简单:

import { Interpreter } from "eval5";

const interpreter = new Interpreter(window);

const result = interpreter.evaluate(`
var a = 100;
var b = 200;
a+b;
`);
console.log(result); // 300

或者

import { Interpreter } from "eval5";

const interpreter = new Interpreter(window, {
	timeout: 1000,
});

let result;

result = interpreter.evaluate("1+1");
console.log(result);

interpreter.evaluate("var a=100");
interpreter.evaluate("var b=200");
result = interpreter.evaluate("a+b");
console.log(result);//300

具体细节可以去项目说明看,最推荐这种方法

二、引入第三方工具Binding

var Binding为引入的第三方工具,以此来代替JavaScript中的eval()函数。附上binding.js的下载链接,提取码: ekfj

使用方法:

修改binding.js中最下方的window.bind=binding为如下:

wx.binding = binding;
console.log("export binding:",wx.binding);

然后在使用eval的地方如下:

var Binding = require('../../utils/binding');

let result = wx.binding.eval(String);
console.log(result);

具体使用方法看这篇文章,本人不太推荐这种方法,因为太占用空间,小程序要求代码总量小于2M,而且对于复杂四则混合运算逻辑有问题。

三、二叉树算法完成简单四则运算

中缀表达式转换为后缀表达式(调度场算法)

  1. 输入队列弹出一个记号
  2. 如果记号为数字,添加到输出队列中
  3. 如果是一个操作符(±*/)则比较它与输出堆栈中栈顶的操作符,如果优先级小于或等于栈顶的操作符,那么将栈顶的操作符弹出并加入输出队列(循环,直到上述条件不满足),最后将本次的操作符压入堆栈。
  4. 如果是一个左括号,压入堆栈
  5. 如果是一个右括号,从栈中不断的弹出操作符,并加入输出队列,知道栈顶的元素为左括号。弹出左括号,不加入输出队列。如果没有发现左括号,说明原来的表达式中括号不对称,有错误。
  6. 如果输入队列为空,而栈中尚有操作符时,如果栈顶的操作符为左括号,则说明原表达式有不匹配的括号。将栈中的操作符逐个弹出,加入输出队列。
  7. 完成

代码转换:

function isOperator(value) {
    var operatorString = "+-*/()";
    return operatorString.indexOf(value) > -1
}
 
function getPrioraty(value) {
    switch (value) {
        case '+':
        case '-':
            return 1;
        case '*':
        case '/':
            return 2;
        default:
            return 0;
    }
}
 
function prioraty(o1, o2) {
    return getPrioraty(o1) <= getPrioraty(o2);
}
 
function dal2Rpn(exp) {
  var inputStack = [];
    var outputStack = [];
    var outputQueue = [];
    let res = '';
    for (var i = 0, len = exp.length; i < len; i++) {
      var cur = exp[i];
      if (cur != ' ') {
        res = res + cur;
        if (i + 1 < exp.length) {
          if (isOperator(exp[i])) {
            inputStack.push(res);
            res = ''
          } else {
            if (isOperator(exp[i + 1])) {
              inputStack.push(res);
              res = ''
            }
          }
        } else {
          inputStack.push(res);
          res = ''
        }
      }
    }
 
    while (inputStack.length > 0) {
        var cur = inputStack.shift();
        if (isOperator(cur)) {
            if (cur == '(') {
                outputStack.push(cur);
            } else if (cur == ')') {
                var po = outputStack.pop();
                while (po != '(' && outputStack.length > 0) {
                    outputQueue.push(po);
                    po = outputStack.pop();
                }
                if (po != '(') {
                    throw "error: unmatched ()";
                }
            } else {
                while (prioraty(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0) {
                    outputQueue.push(outputStack.pop());
                }
                outputStack.push(cur);
            }
        } else {
            outputQueue.push(new Number(cur));
        }
    }
 
    if (outputStack.length > 0) {
        if (outputStack[outputStack.length - 1] == ')' || outputStack[outputStack.length - 1] == '(') {
            throw "error: unmatched ()";
        }
        while (outputStack.length > 0) {
            outputQueue.push(outputStack.pop());
        }
    }
 
    return outputQueue;
 
}

计算结果:

function evalRpn(rpnQueue) {
    var outputStack = [];
    while (rpnQueue.length > 0) {
        var cur = rpnQueue.shift();
 
        if (!isOperator(cur)) {
            outputStack.push(cur);
        } else {
            if (outputStack.length < 2) {
                throw "unvalid stack length";
            }
            var sec = outputStack.pop();
            var fir = outputStack.pop();
 
            outputStack.push(getResult(fir, sec, cur));
        }
    }
    if (outputStack.length != 1) {
        throw "unvalid expression";
    } else {
        return outputStack[0];
    }
}
function getResult(first, second, operator) {
    var result = 0;
    switch (operator) {
        case '+':
            result = first + second;
            break;
        case '-':
            result = first - second;
            break;
        case '*':
            result = first * second;
            break;
        case '/':
            result = first / second;
            break;
        default:
            return 0;
    }
 
    //浮点数的小数位超过两位时,只保留两位小数点
    function formatFloat(f, digit) {
        //pow(10,n) 为 10 的 n 次方
        var m = Math.pow(10, digit);
        return parseInt(f * m, 10) / m;
    }
    return (formatFloat(result, 2));
}

使用方法:

let result = evalRpn(dal2Rpn('3 *4 +5+7'));
console.log(result);//24

引用这篇文章

 类似资料: