每段JavaScript代码块都是按顺序 自成体系处理的。

在浏览器中,同一个文档所有的脚本都运行在同一个执行环境里,共享同一个沙箱。

每段代码块处理的过程按顺序包括三个步骤:源码处理函数解析代码执行

源码处理

源码处理阶段会检查脚本代码块里的语法,如果源码处理阶段出错,那么整个代码块都会被弃用;之后解析器则会继续处理下面的代码块。

假设眼前的HTML文档中包含如下代码。

<!--代码块一-->
<script>
  var var1 = 1;
  var var2 =
</script>

<!--代码块二-->
<script>
  2;
</script>

JavaScript引擎会先处理第一个代码块,在处理第一个代码块时,发现了语法错误,因此整个代码块被弃用。

然后再解析第二个代码块,第二个代码块无语法错误,因此会继续进行第二个阶段【函数解析】。

函数解析

这个阶段是JavaScript解析器对当前代码块所有具名的全局函数进行识别并注册。

因此下面这两种写作方式均可实现相同效果。

<script>

  sayHello();

  function sayHello(){
    console.log('HelloWorld');
  }

</script>
<script>

  function sayHello(){
    console.log('HelloWorld');
  }

  sayHello();

</script>

不过需要额外注意的是,第二阶段的这种全局名称解析模式只对函数有效,向下面这种形式,则不会被提前注册。

<script>

  var say_hello = function (){
    console.log('HelloWorld');
  }

</script>

因此下面整个代码块在最终执行的时候会报错。

<script>

  say_hello();

  var say_hello = function (){
    console.log('HelloWorld');
  }

</script>

代码执行

第二阶段完成后,便会开始第三阶段:

JavaScript引擎开始按顺序执行所有在具名函数区块之外的所有代码。

请看如下代码

<script>

  function say_hello(){
    console.log('HelloWorld');
  }

  function say_hi(){
    console.log('Hi');
    say_bye();
  }

  console.log('[start]');
  say_hi();
  console.log('[starting]');

</script>

<script>

  say_hello();
  console.log('[end]');

</script>

[源码处理] 正常

[函数解析] 注册函数say_hello、say_hi

[代码执行]

第一个代码块

<script>

  console.log('[start]');  
  say_hi();  
  console.log('[starting]');

</script>

输出 [start]

调用say_hi函数

----输出 hi

----调用say_bye函数时,抛出异常,跳出代码块

第二个代码块

<script>

  say_hello();
  console.log('[end]');

</script>

输出 HelloWorld

输出 [end]