eval5 - 基于JavaScript编写的JavaScript解释器

背景

由于之前项目中为了最求最大灵活度,部分功能预留了JavaScript脚本配置入口,如有特殊需求的情况下可不修改代码实现个性化需求。
例如:报表设计中的图形组件,可能不同的报表展示形式多样,此时的界面配置无法提前预设所有可能的情况,如果在图形渲染将前端生成的配置参数交给预先配置好的JavaScript脚本进行特殊处理就可以完成个性需求。但该功能需要动态执行JavaScript脚本,前端只能通过eval Function方式来动态执行,这种运行方式在浏览器模式下是没问题,但在不支持eval Function的运行环境就无法实现上述需求,例如:微信小程序。

eval5是完全基于JavaScript编写的JavaScript解释器,支持ECMA5语法。

项目地址:https://github.com/bplok20010...

在线体验:https://bplok20010.github.io/...

运行原理

步骤一: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;
    }
}

运行原理.png

生成 抽象语法树这一步已经有很多优秀的开源库,如: esprima acorn babylon ...

步骤二执行大概如下:

  1. 先遍历语法树,找出函数声明及变量声明,因为有作用域提升。
  2. 开始执行语句或表达式,建立作用域。(此步骤非常关键)
  3. 根据不同的语法节点type执行对应的处理方法,并得到最后一个表达式返回值。例如BinaryExpression节点则调用handleBinaryExpression方法
更多实现细节就不详细讲解,有兴趣的可直接到github上看 源码

需要注意的两点:

  • 作用域处理
  • 函数创建及调用

运行效果

可将es5代码直接粘贴到文章开头的体验地址并运行查看效果。以下是运行echarts的效果示例:

  1. 复制https://cdn.jsdelivr.net/npm/... 代码到在线体验中运行。
  2. 复制以下echart代码并运行
//设置在线体验容器高度
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);      

效果如图:
效果.png

使用场景

不支持eval Function的运行环境,例如:微信小程序,小程序开发用户可直接看这篇介绍:小程序eval/Function终极替代方案:eval5

你可能感兴趣的:(javascript,typescript,前端,小程序,编译原理)