由于之前项目中为了最求最大灵活度,部分功能预留了 JavaScript 脚本配置入口,如有特殊需求的情况下可不修改代码实现个性化需求。
例如:报表设计中的图形组件,可能不同的报表展示形式多样,此时的界面配置无法提前预设所有可能的情况,如果在图形渲染将前端生成的配置参数交给预先配置好的 JavaScript 脚本进行特殊处理就可以完成个性需求。但该功能需要动态执行 JavaScript 脚本,前端只能通过eval
Function
方式来动态执行,这种运行方式在浏览器模式下是没问题,但在不支持eval
Function
的运行环境就无法实现上述需求,例如:微信小程序。
eval5 是完全基于 JavaScript 编写的 JavaScript 解释器,支持完整 ECMA5 语法。
项目地址: https://github.com/bplok20010/eval5
在线体验: https://bplok20010.github.io/eval5
步骤一:eval5 通过acorn
将源码编译得到树状结构的抽象语法树(AST)。
抽象语法树由不同的节点组成,每个节点的 type 标识着不同的语句或表达式,例如: 1+1 的抽象语法树:
{
"type": "Program",
"body": [
{
"type": "ExpressionStatement",
"expression": {
"type": "BinaryExpression",
"operator": "+",
"left": {
"type": "Literal",
"value": 1,
"raw": "1"
},
"right": {
"type": "Literal",
"value": 1,
"raw": "1"
}
}
}
],
"sourceType": "script"
}
步骤二:为不同的节点 type 编写不同的处理模块并得到最终结果。例如:根据 1+1 的语法树我们可以写出一下解释器代码:
function handleBinaryExpression(node) {
switch( node.operator ) {
case '+':
return node.left.value + node.right.value;
case '-':
return node.left.value - node.right.value;
}
}
生成
抽象语法树
这一步已经有很多优秀的开源库,如:esprima
acorn
babylon
...
步骤二执行大概如下:
type
执行对应的处理方法,并得到最后一个表达式返回值。例如BinaryExpression
节点则调用handleBinaryExpression
方法更多实现细节就不详细讲解,有兴趣的可直接到 github 上看源码。
需要注意的两点:
可将 es5 代码直接粘贴到文章开头的体验地址并运行查看效果。以下是运行 echarts 的效果示例:
//设置在线体验容器高度
root.style.height = '300px';
// 基于准备好的 dom,初始化 echarts 实例
var myChart = echarts.init(document.getElementById('root'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
效果如图:
不支持eval
Function
的运行环境,例如:微信小程序,小程序开发用户可直接看这篇介绍:小程序 eval/Function 终极替代方案:eval5