预编译
JavaScript引擎的两大步骤是:
预编译(第一次、前置扫描)
解释执行
预编译—脚本阶段
脚本:
1.创建全局对象GO(window)(上下文)
2.加载脚本文件
3.预编译:
(1)找到所有的变量声明,按照变量名加入全局对象,如果已经存在,忽略。
(2)找出所有的变量的声明,按照变量名加入全局对象,如果出现已经存在的变量名或者函数名,替换。
注 :非声明不予理睬。
// 脚本的预编译:
- 没有var的变量,都不是变量声明,全部都认为是window的全局变量,不参与预编译:
- 即使aa在函数中,aa也是全局变量,是运行时生效,不是预编译时生效
- 脚本中,所有的变量声明,在脚本的预编译阶段完成,所有变量的声明与实际的书写位置无关.
- 脚本中,所有的函数声明,在脚本的预编译阶段完成,所有函数的声明与实际的书写位置无关.
- 脚本中,如果变量与函数同名,那么函数将覆盖变量
- 脚本中,如果变量与函数同名,函数可以覆盖变量,但是变量无法覆盖函数
- 脚本中, 如果有多个函数同名,最后声明的函数将覆盖所有前面的同名函数声明
例如上面的例子中的分析:
首先预编译脚本阶段:
生成一个全局变量GO。
然后找到变量的声明和函数的声明。
过程:
首先发现了一个变量名为a的变量:
GO.a -->undefind(预编译的脚本阶段的话,a的值初始为undefined)
继续向下发现了一个函数的声明:
GO.b -->function(){}
GO.c -->undefind
继续执行的过程中发现有个名为a的函数的声明
所以这个时候a的函数声明会替换掉变量a
GO.a -->function(){}
这个时候预编译的过程结束 开始进行解释执行的阶段:
这个时候读取到把1赋值给了a 所以这个时候:
GO.a -->function(){} -->1
下面的是函数的声明 所以继续往下执行。
这个时候发现变量c被赋值了一个函数。
GO.c -->undefind --> function(){}
所以脚本阶段的预编译和解释执行完之后的结果为:
GO.a --> 1
GO.b -->function(){}
GO.c -->function(){}
预编译–函数调用阶段
函数调用:
1.创建活动对象AO(Active Object)(上下文)
2.预编译: