在js引擎解释执行代码之前会有一个预编译的过程
了解预编译的过程,对于我们理解js代码的执行有很重要的意义,例如,为何函数的执行可以放在函数声明之前,而变量的使用放在变量定义之前则会报出undefined,而使用没有定义的变量又会直接报错。
下面来看一下其原理吧。
(一)预编译的过程
对于全局代码,预编译分为三步:
一、检查var定义的变量,并存储于全局对象GO中,但此时并不赋值,GO(global object)是全局执行上下文,也就是window对象。
二、检查函数定义,并存储于GO,此时其只存储函数名于其函数表达式所在的地址,并不看表达式的具体内容。
三、执行函数体。
而在执行函数时,也会进行预编译,其预编译过程有四步:
一、检查var定义的变量,并存储于AO中,此时并不赋值。AO(Activation Object)是函数执行上下文,在函数开始执行是创建(即预编译之前)。
二、检查函数体内的参数,并将其替换为传入的参数arguments[i]。
三、检查函数定义,并存储于AO。
四、执行函数体。
注意:
一、对于变量,预编译过程中只是声明,而并不赋值,如下例所示:
<script>
console.log(a)
var a = 5
</script>
由于在预编译中,没有对a赋值,在函数体执行之前,GO = {a: undefinrd, …},所以控制台输出undefined
赋值会在函数体执行的过程中给进行。
二、对于函数,预编译时会把函数表达式的内存地址同函数名存进所以,函数的声明和执行语句可以逆序。
(二)扩展
函数预编译过程中用到的GO、AO涉及到了函数作用域和作用域链的问题,也跟预编译的过程相关,将在下个博文讨论。