javascript - 浏览器是真正逐行读取 JavaScript 还是多次通过?

标签 javascript browser interpreter

我知道 JavaScript 是被解释的,而不是被编译的。没有问题。但是,我一直在这里读到 JavaScript 是“动态”执行的,并且一次读取一行。当涉及到以下示例时,这个想法让我很困惑:

writeToConsole();

function writeToConsole() {
    console.log("This line was reached.");
}

为了记录,这段代码将很好地写入控制台。尽管如此,浏览器如何知道 exampleFunction() 的存在?如果还没有达到这个功能呢?

换句话说,这个函数是什么时候第一次被解释的?

最佳答案

首先,您做出了错误的假设:编译了现代 JavaScript。引擎如 V8 , SpiderMonkey , 和 Nitro 将 JS 源码编译成原生 machine code主机平台的。

即使在较旧的引擎中,也不会解释 JavaScript。他们将源代码转换为 bytecode , 引擎的 virtual machine执行。

这实际上是 Java 和 .NET 语言中的工作方式:当您“编译”应用程序时,实际上是将源代码转换为平台的字节码,Java bytecodeCIL分别。然后在运行时,一个 JIT compiler将字节码编译成机器码。

实际上只有非常古老和简单的 JS 引擎 interpret JavaScript 源代码,因为解释很慢。

那么JS编译是如何工作的呢?在第一阶段,源文本被转换为 abstract syntax tree (AST) ,一种数据结构,以机器可以处理的格式表示您的代码。从概念上讲,这很像 HTML 文本如何转换为其 DOM表示,这是您的代码实际使用的内容。

为了生成 AST,引擎必须处理原始字节的输入。这通常由 lexical analyzer 完成.词法分析器并没有真正“逐行”读取文件;而是逐字节读取,使用语言的语法规则将源文本转换为标记。然后词法分析器将 token 流传递给 parser ,这就是实际构建 AST 的原因。解析器验证 token 形成有效序列。

您现在应该能够清楚地看到为什么语法错误会阻止您的代码工作。如果源文本中出现意外字符,引擎将无法生成完整的 AST,也无法进入下一阶段。

一旦引擎有了 AST:

  • 解释器可能只是直接从 AST 开始执行指令。这是非常缓慢的。
  • JS VM 实现使用 AST 生成字节码,然后开始执行字节码。
  • 编译器使用 AST 到 generate machine code ,由 CPU 执行。

  • 因此,您现在应该至少可以看到,JS 执行分两个阶段进行。

    但是,执行阶段实际上对您的示例工作的原因没有影响。它的工作原理是 rules定义如何评估和执行 JavaScript 程序。规则可以很容易地以一种方式编写,使您的示例不起作用,而不会影响引擎本身实际解释/编译源代码的方式。

    具体来说,JavaScript 有 a feature俗称吊装。为了理解提升,您必须了解函数声明和函数表达式之间的区别。

    简单地说,函数声明是当你声明一个将在别处调用的新函数时:
    function foo() {
    
    }
    

    函数表达式是当您使用 function 时任何需要表达式的地方的关键字,例如变量赋值或参数:
    var foo = function() { };
    
    $.get('/something', function() { /* callback */ });
    

    JavaScript 要求在执行上下文开始时将函数声明(第一种类型)分配给变量名,不管 声明出现在源文本(上下文)中的位置。执行上下文大致等同于作用域——简单来说,就是函数内部的代码,或者如果不在函数内部,则是脚本的最顶部。

    这可能会导致非常奇怪的行为:
    var foo = function() { console.log('bar'); };
    
    function foo() { console.log('baz'); }
    
    foo();
    

    您希望将什么记录到控制台?如果你只是线性地阅读代码,你可能会认为 baz .但是,它实际上会记录 bar ,因为foo的声明被提升到赋值给 foo 的表达式之上.

    所以总结一下:
  • JS 源代码永远不会逐行“读取”。
  • JS 源代码实际上是在现代浏览器中编译的(真正意义上的)。
  • 引擎在多次通过中编译代码。
  • 行为是您的示例是 JavaScript 语言规则的副产品,而不是它的编译或解释方式。
  • 关于javascript - 浏览器是真正逐行读取 JavaScript 还是多次通过?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15395347/

    相关文章:

    javascript - 使 html 看板可滚动

    javascript - 连接到 meteor 应用程序的多个子域

    javascript - PHP 将多个带有标题的文件上传到 MySQL

    algorithm - 在 brainfuck 程序中检测无限循环

    javascript - 如何从 coldfusion cfc 页面获取返回变量?

    javascript - 如何使用 jQuery 或 javascript 保留 cookie 而不更改浏览器设置?

    c# - 将参数传递到 WebBrowserDocumentCompleted

    javascript - 如何使用 javascript/Extjs 制作默认横向打印?

    python - 编译Python,为什么会忽略一些错误的东西?

    interpreter - Free Pascal 有命令行解释器吗?