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

引言

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

引用这篇文章

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 微信小程序eval函数已经被禁用,不能直接使用eval函数在执行字符串时,可能会引起安全漏洞和代码注入等问题。为了保障小程序的安全性,微信官方决定禁用eval函数。 如果您在开发小程序时需要执行一些动态的代码,可以使用Function构造函数来代替eval函数。例如,下面的代码使用Function构造函数动态执行一个简单的加法运算: ``` var a = 1; var b = 2; var result = new Function('return ' + a + '+' + b + ';')(); console.log(result); // 3 ``` 需要注意的是,使用Function构造函数创建函数时,functionBody 参数必须是一个字符串,而不能是一个函数对象。同时,为了避免代码注入等安全问题,应该避免使用动态的代码字符串。 ### 回答2: 微信小程序 eval 是一个用于执行传入的 JavaScript 字符串的函数。它可以将字符串代码作为参数传入,然后动态地在小程序执行代码并返回结果。eval 函数在一些特定场景下非常有用,例如在小程序需要动态地生成代码并执行时。 eval 函数的使用方法很简单,只需要将需要执行的代码字符串作为参数传入即可。例如,我们可以使用 eval 函数来执行一个简单的加法运算: ```javascript var a = 10; var b = 20; var result = eval("a + b"); console.log(result); // 输出 30 ``` 在上面的例子,我们将字符串 `"a + b"` 作为参数传入 eval 函数,并将返回的结果赋值给 result 变量。最后,我们使用 console.log 输出了结果。 需要注意的是,eval 函数的使用需要谨慎,尤其是在处理用户输入或者网络请求返回的动态代码时。由于 eval 函数会执行传入的字符串代码,如果不对传入的代码进行严格的验证和限制,可能会造成安全风险。攻击者可能利用 eval 函数来注入恶意代码,从而对用户隐私或者系统进行攻击。因此,在使用 eval 函数时应该遵循安全规范,并对传入的代码进行充分的验证和过滤。 总而言之,微信小程序eval 函数可以用于执行传入的字符串代码,并返回执行结果。它在一些特定场景下非常有用,但需要小心使用以避免安全风险。 ### 回答3: 微信小程序 eval 是一种开发工具,它主要用于对某一段 JavaScript 代码进行动态求值并返回结果。eval 函数接受一个字符串作为参数,这个字符串可以包含变量、函数、表达式等 JavaScript 代码。 使用 eval 函数可以实现动态化的功能,例如根据用户的输入动态执行不同的代码逻辑,实现个性化定制。同时,它可以用于处理一些动态生成的代码,如模板引擎、动态渲染等。 值得一提的是,由于 eval 函数的执行过程是在当前的作用域下执行的,如果在 eval 定义了新的变量或函数,它们都将在 eval 函数执行结束后失效,不会对外部环境造成污染。 微信小程序 eval 还封装了一些安全处理机制,以防止恶意注入或代码劫持。例如,它只支持在小程序自身定义的函数使用 eval 函数,禁止在外部引入的库或组件使用 eval,从而保证了代码的安全性。 同时,开发者也需要注意 eval使用场景和使用方式。由于 eval 函数的执行效率较低,并且存在一些安全隐患,所以在开发过程应尽量避免过度使用 eval 函数,以免影响程序的性能和安全性。在需要使用 eval 函数的情况下,可以通过其他方式来替代,如利用 JavaScript 的原生语法,或者使用其他适合的小程序 API。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

please叫我滚去学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值