全局预处理与执行
js解析代码时,并不是读一行处理一行的,而是会有一个预处理阶段。
预处理阶段,只要满足以下两个条件:
- 用声明的方式创建的函数,即如下形式:
function xxx(){
}
- 用var定义的变量
js就会将查找到的函数或者变量名放到词法环境中去,如下
lexicalEnvironment{
变量名:undefined;
函数名:对函数的一个引用
}
比如下列代码
var a=5;
function xxx(){
}
此时创建的词法环境为
lexicalEnvironment{
a:undefined;
xxx:保存对xxx函数的引用
}
如果没有用var定义,而是全局变量的话,并不会加到词法环境中去。如下:
console.log(a); //undefined
console.log(b); //报错:b is not defined
var a=5;
b=6;
其实此时的a输出undefined,也就是我们平常所说的var定义的变量会存在“变量提升,赋值不提升”了。
在代码的执行阶段,执行原则如下:
- 代码会从上往下执行
- 遇到存在于词法环境中的变量时进行赋值
- 遇到不存在词法环境中的变量时,js将一次性执行声明,即让变量成为词法作用域的成员并进行赋值操作。一步到位~
小测试来啦,请分析以下代码的输出:
alert(a);
alert(b);
alert(f);
alert(g);
var a=5;
b=6;
alert(b);
function f() {
console.log('f');
}
var g=function () {
console.log('g');
}
alert(g);
当当,正确输出结果是:
- undefined
- 报错:b is not undefined(此时一旦报错后面代码就不执行了,所以可将上述程序代码中 alert (b)注释掉 再查看后续结果)
- 以字符串的形式显示的f函数

- undefined 因为g是以函数表达式的方法进行定义的,预处理时不会添加到词法作用域里
- 6 //即第二个alert (b)的结果
- 以字符串的形式显示的g函数,即第二个alert(g)的结果

个人小总结:变量没添加到词法作用域时,会报错;而函数没添加到词法作用域时,会undefined;
函数预处理与执行
函数是可以调用多次的,每调用一次,会产生一个词法环境对象,全局预处理中这个环境对象指的就是window对象,在函数预处理中,该对象不可见,无法访问,是解析器的东西。
如果函数中有两个参数,但是调用时只传入了一个,即
function aaaa(a,b){
}
aaaa(1)
此时的词法环境对象为
leEnvironment{
a:1
b:undefined
}
如果函数中有两个参数,调用时也传入了两个,但是都有变量冲突:
function f(a,b) {
alert(a);
alert(b);
var b = 100;
function a() {
}
}
f(1,2); //函数调用传入了两个参数
此时传入的参数a=1和function a的函数名a冲突; 调用时传入的参数b=2和内部定义的b=100冲突
正确输出为:

- 2
即传入参数与内部函数名冲突时,函数是一等功名;而传入参数和内部自定义参数冲突时,使用的仍是调用时传入的参数值。