变量提升、预编译过程
function fn(c){
console.log(c);
var c = false;
console.log(d);
console.log(a);
var a = 1;
function a(){
};
console.log(a);
b();
var b = function(){
console.log("函数表达式");
}
function b(){
console.log( "函数声明" )
}
b();
function d(){}
}
fn(true);
首先,全局js在执行前会产生一个GO(Globa Object),也就是我们常说的全局作用域。
全局代码在执行的时候,先是变量提升,在全局作用域内添加属性值为undefined,然后是函数(以函数声明方式创建的函数)提升,再是代码执行。
当一个方法被调用的时候会形成一个局部作用域AO(Activation Object)。
函数在被调用的时候,以上面的fn这个方法为例,进入函数上下文,但是在执行代码之前,经历的阶段:
第一阶段:首先创建一个AO:
AO : {
}
第二阶段:将形参与变量作为属性名放入AO中,值为undefined,如果存在相同变量名会直接覆盖
AO : {
c: undefined,
a: undefined,
b: undefined,
d: undefined
}
第三阶段:将实参与形参统一
AO : {
c: true,
a: undefined,
b: undefined,
d: undefined
}
第四阶段:函数声明提升
AO : {
c: true,
a: function a(){},
b: function b(){console.log( "函数声明" )},
d: function d(){}
}
接下就是执行函数内部的代码了。
-
console.log(c)的时候,在AO中可以看到c的值为true,接下来c被赋值为false。
-
console.log(d),打印d这个函数的函数体function b(){}。
-
console.log(a),打印a这个函数的函数体function a(){}。
-
接下来a被赋值成了1,下面的function a(){}跳过。
-
再次打印console.log(a)输出1。
-
直接执行b这个方法,那么很打印输出“函数声明”。
-
b被赋值成了另外一个函数function b(){console.log( "函数表达式" )}。
-
function b(){ console.log( "函数声明" ) }函数体跳过。
-
那么我们再执行b这个函数的时候,b函数已经被重新赋值,打印的肯定是“函数表达式”。
-
function d(){}函数体跳过。
-
执行完毕,销毁fn这函数的AO(如果存在闭包,则内存不能被回收!)。