javascript中,代码的解析分为两个阶段,变量初始化阶段和代码执行阶段。
变量初始化阶段
- 函数参数(若未传入,则初始化值为undefined)
函数声明(若发生命名冲突,会覆盖)
function foo(x){ function x(){};//函数声明覆盖了参数x console.log(x); } foo(34); //输出'function x(){}'
变量声明(初始化变量值为undefined,若发生命名冲突,会忽略)
function foo3(){ function z(){}; var z; //变量声明冲突,则忽略该声明。 console.log(z); } foo3();//输出'function x(){}'
代码执行阶段
注意,函数变量初始化阶段和代码执行阶段是两个不同的阶段,代码执行阶段将按顺序给代码赋值。如下代码,虽然在变量初始化阶段,z会被函数声明覆盖,但等到代码执行阶段,z又重新被赋值为10。因此,最终z的输出结果仍然为10。
function foo2(){
var z = 10;
function z(){};
console.log(z);
}
foo2(); //'10'
function foo4(x,y,x){
function z(){};
var z = 10;//在变量初始化阶段被忽略,在函数执行阶段覆盖z函数
console.log(z);
}
foo4();//10
代码分析
function example(){
console.log(x); //'function x(){}'
var x = 10;
console.log(x);//'10'
x = 20;
function x(){}
console.log(x);
if (true) {
var a = 1;
}else{
var b = true;
}
console.log(a);//1
console.log(b);//undefined
console.log(c);//
};
example();//ReferenceError: c is not defined
如上代码,在变量初始化阶段,第一步,先初始化函数参数,此处没有传入任何参数,因此,初始化的参数个数为0。第二步,初始化函数声明,因此function x(){}的声明被提前。第三步,初始化变量声明,第一个变量为x,因为已经声明了同名函数x,因此变量x的声明被忽略;所以,只声明了变量a和b,在这一阶段,变量a和b的值都为undefined。
接着,进入代码执行阶段,代码将按顺序执行。第一句代码输出x,因为在初始化阶段,x已被声明为函数,因此会输出‘function x(){}’。第二句代码,会执行赋值操作,重新将x赋值为10。第三句代码再次输出x,则为‘10’。第四句代码重新将x赋值为20。第五句代码已经在变量初始化阶段完成了声明,因此此时将被忽略。第六句代码再次输出x,此时将输出‘20’。接下来为判断语句,因为条件为true,所以将变量a赋值为1,此时,没有对变量b进行赋值,所以,变量b的值仍为undefined。最后,输出a,为‘1’;输出b,值为‘undefined’。如果输出的是一个未声明的变量,如最后一句代码,输出c,则会报错:‘ReferenceError: c is not defined’。