宝哥软件园

用js编写js解释器过程的详细说明

编辑:宝哥软件园 来源:互联网 时间:2021-08-21

用js编译js看似是一件高大上的事情,但实际原理其实很简单,无非就是用js对象属性用字符串来表达这个特性可以实现的黑魔法。

之所以看起来这么深奥,可能是因为网上现有的教程总是以一个babylon/@babel/parser开头,让大家先看一堆ASTs,再贴一堆代码。

递归AST直接处理所有类型的节点。最后,它成功地吓跑了像我这样的新手。

所以今天写这篇文章的目的是给大家一个js2js教程,简单易懂,在连刚学习JS的人都能看懂。

我们先来看看效果

最简单的口译员之一

如上所述,js有一个特性,对象属性可以用字符串表示。例如,console.log相当于console['log']。根据这个特性,我们可以写一个兼容性差,极度简单的原型。

函数callFunction(fun,arg){ this[fun](arg);} callFunction('alert ',' hello world ');//如果您在浏览器环境中,应该会弹出一个弹出窗口。既然是简单的版本,那肯定问题很多。js中的语法不仅仅是一个函数调用。让我们看看黑魔法是如何实现赋值的。

函数declaraverible(key,value){ this[key]=value;} declaraverible . call(window,' foo ',' bar ');//window . foo=' bar ' tips : const可以使用Object.defineProperty实现;

如果上面的代码可以理解,那么你已经知道js解释器的基本原理了。如果你不能理解它,你必须责备我。

稍微加强一下

可以看出,为了方便,我们把函数调用写成了call function(‘alert’,‘hello world’);但它看起来一点也不像js解释器。我们心中想要的解释器至少应该看起来像parse(‘alert(‘hello world’)’),所以让我们做一点修改。这里我们将介绍巴别塔。

但是不用担心,我们解析的语法树(AST)也很简单。

从“@babel/parser”导入babelParserconst code='alert('hello world!')';const ast=babelParser.parse(代码);上述代码解析了以下内容

{ 'type': 'Program ',' start': 0,' end': 21,' body ' :[{ ' type ' 3: ' expression statement ',' start ' : 0 0,' end': 21,' expression ' : { ' type ' : ' CallExpression ',' start ' : 21,' end '被调用者' : ' { ' type ',' raw': ''hello world!'}]}],' source type' :' module'}看起来很多,但我们实际使用的其实只是一小部分,可以稍微简化一下,去掉暂时不用的字段

{ 'type': 'Program ',' body ' :[{ ' type ' : ' expression statement ',' expression ' : { ' type ' : ' CallExpression ','被调用者' : { 'type': 'Identifier ',' name ' : ' alert ' },'引数' 3:[{ ' type ' : ' Literal ',' value ' : ' hello world!',}]}}],}我们先浏览AST中所有属性名为type的数据。

有四种类型的表达式语句调用表达式标识符文字,所以我们将分别分析这四个节点,从最简单的一个开始

逐字的

{ 'type': 'Literal ',' value': 'hello world!',}对于Literal内容,我们只需要一个value属性,可以直接返回。

if(node . type===' Literal '){ return node . value;}很简单吗?

标识符

{'type' :' identifier ',' name' :' alert'},identifier也很简单,它代表一个已存在的变量,变量名是node.name,既然是已存在的变量,它的值是多少?

if(node.type==='Identifier') {返回{ name: node.name,value : this[node . name]};}我们从node.name获得的上述警报是一个字符,通过这个['

更多资讯
游戏推荐
更多+