JavaScript-变量提升(AO、GO)

1,899 阅读2分钟

变量提升、预编译过程

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(如果存在闭包,则内存不能被回收!)。