eval5 - 基于 Javascript 编写的 Javascript 解释器 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
nobo
V2EX    程序员

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

  •  1  
  •   nobo 2020-03-08 23:00:37 +08:00 1913 次点击
    这是一个创建于 2050 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    由于之前项目中为了最求最大灵活度,部分功能预留了 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; } } 

    运行原理.png

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

    步骤二执行大概如下:

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

    更多实现细节就不详细讲解,有兴趣的可直接到 github 上看源码

    需要注意的两点:

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

    运行效果

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

    1. 复制https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js 代码到在线体验中运行。
    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

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1065 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 18:28 PVG 02:28 LAX 11:28 JFK 14:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86