我试图了解 JS 是如何被实际解析的。但是我的搜索要么返回一些文档非常模糊的“解析器/生成器”项目(我什至不知道那是什么意思),或者如何使用 JS 引擎使用神奇的“解析”方法解析 JS。我不想扫描一堆代码并尝试一生去理解(虽然我可以,但这需要太长时间)。
我想知道 JS 代码的任意字符串实际上是如何变成对象、函数、变量等的。我还想知道将字符串变成东西、存储、引用、执行的过程和技术。
是否有任何文档/参考资料?
我试图了解 JS 是如何被实际解析的。但是我的搜索要么返回一些文档非常模糊的“解析器/生成器”项目(我什至不知道那是什么意思),或者如何使用 JS 引擎使用神奇的“解析”方法解析 JS。我不想扫描一堆代码并尝试一生去理解(虽然我可以,但这需要太长时间)。
我想知道 JS 代码的任意字符串实际上是如何变成对象、函数、变量等的。我还想知道将字符串变成东西、存储、引用、执行的过程和技术。
是否有任何文档/参考资料?
解析器可能以各种方式工作,但从根本上说,它们首先经过一个标记化阶段,然后将结果提供给编译器,如果可以的话,编译器会将其转换为程序。例如,给定:
function foo(a) {
alert(a);
}
解析器将删除任何前导空格到第一个字符,字母“f”。它将收集字符,直到它得到不属于的东西,即表示令牌结束的空格。它再次从 "foo" 的 "f" 开始,直到到达 "(",所以它现在有标记 "function" 和 "foo"。它知道 "(" 本身就是一个标记,所以是 3令牌。然后它得到“a”,后跟“)”,这两个令牌组成 5,依此类推。
空格的唯一需要是在其他不明确的标记之间(例如,“function”和“foo”之间必须有空格或另一个标记)。
一旦标记化完成,它就会进入编译器,编译器将“function”视为标识符,并将其解释为关键字“function”。然后它得到“foo”,语言语法告诉它的标识符是函数名。然后“(”表示一个开放的分组运算符,因此是一个形式参数列表的开始,依此类推。
编译器可能一次处理一个令牌,或者可能会分块抓取它们,或者做各种奇怪的事情来使它们运行得更快。
您还可以阅读C/C++ 解析器如何工作?,这提供了更多线索。或者只是使用谷歌。
虽然它与真正的 JS 引擎的工作方式并不密切对应,但您可能有兴趣阅读 Douglas Crockford 的关于Top Down Operator Precedence的文章,其中包括使用它解析的 Javascript 子集编写的小型工作词法分析器和解析器的代码。它是非常易读且简洁的代码(附带很好的解释),它至少为您提供了实际实现如何工作的概要。
比 Crockford 的“Top Down Operator Precedence”更常用的技术是递归下降解析,在Narcissus中使用,JS 中 JS 的完整实现。