JavaScript中的eval函数是颇受开发者争议的问题之一,问题主要在于其可能导致的不安全性,因此它也遭到了微信官方的封禁。记得以前有些人想用eval实现热更新代码,而不用经过审核,封掉这类型的代码是正常的。但是,eval函数的优点也是很明显的。例如,使用JS编写一个计算器程序,在遇到"2+1-3*5"这样的字符串时,使用eval就可以很容易地计算出,类似如:
var result="2+1-3*5";
console.log(eval(result));
那我们是否就真的要和eval说再见了呢,不是的,下面有几种解决方案可以替代eval。
eval5是基于 TypeScript 编写的 JavaScript 解释器,支持完整 ES5 语法支持浏览器、node.js、小程序等 JavaScript 运行环境
可用于:
我们可以通过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
具体细节可以去项目说明看,最推荐这种方法
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,而且对于复杂四则混合运算逻辑有问题。
代码转换:
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
引用这篇文章。