每段
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]