讲一讲javaScript预编译

前置:

首先我们得理解js运行顺序:

  1. 语法分析
  2. 预编译
  3. 解释执行

而在预编译过程中,会有两种提升:

  1. 函数声明整体提升:就是把任意位置的函数的声明都提到逻辑最前面
  2. 变量声明提升:把变量的声明也提到最前面。

那么什么叫函数声明和变量声明呢?
例如:

function a(){
    
    };//这叫做函数声明
var b = function b(){
    
    };//这个不是函数声明
var a =123;//这其实是两句话,其中var a;就是变量声明,而后面a=123;叫做变量赋值

我们再来看什么叫提升:

function fn(a){
    
    
           console.log(a);
           var a =123;
           console.log(a);
           function a(){
    
    }
           console.log(a);
           var b = function(){
    
    }
           console.log(b);
           function d(){
    
    }
}
fn(1);

提升之后:

 function fn(a){
    
    
            var a;var b;
            function a(){
    
    }
            function d(){
    
    }
            
            console.log(a);
            var a =123;
            console.log(a); 
            console.log(a);
            var b=function(){
    
    }
            console.log(b);
            
        }

全局和局部

下面我们再来理解两个概念:

  • 全局变量
  • 局部变量

全局变量(GO):

  • 作用域是全局
  • 任何变量,假如未经声明就赋值,那么它就是全局变量
  • 一切作用域在全局时的声明变量,也是全局变量
  • 一切声明的全局变量都是window的属性

局部变量

  • 写在函数体内的已声明变量

示例:

        var a =123;
         b=123;
        console.log(window.a);    //123
        console.log(window.b);   //123

        function test(){
    
    
            var a=c=1234;
            console.log(a);      //1234
            console.log(c);      //1234
        }
        test();

解释:a是声明的全局变量,就是window.a,因此第一个是123,第二个b是未经声明的全局变量,就是window.b,因此第二个是123

接下来来看test函数里面的执行顺序:
赋值顺序都是自右向左,因此我们将其拆分成:

扫描二维码关注公众号,回复: 12302957 查看本文章
   c=1234;
   a=c;
   var a;

而c属于未声明变量,我们将其直接提升一个段位,即全局变量中,即window.c,再将1234赋值给c,c再赋值给a

函数预编译四步走:

  1. 创建AO对象Activation Object(执行期上下文),作用是理解的作用域

  2. 形参和变量声明,将变量和形参名作为AO属性名,值为undefined,相当于
    AO{
    a:undefined;
    b:undefined;
    }

  3. 将实参和形参相统一(把实参传到形参里)

  4. 在函数里面找函数声明,值赋予函数体
    (这里注意,假如自己AO里有,那么就不用去找GO)

例如:

   function test(a,b){
    
    
            console.log(a);
            c=0;
            var c;
            a=3;
            b=2;
            console.log(b);
            function b(){
    
    }
            function d(){
    
    }
            console.log(b);
        }
        test(1);
    // 第一步,创建AO
    // 第二步,AO中有a,b,c:undefined
    // 第三步,a:1,   b,c还是undefined
    // 第四步, a: 1  b:function b(){}  c:undefined    d:function d(){}

然后开始执行,此时执行的时候代码内应该是这样(注释掉的已经预编译过):


        function test(a,b){
    
    
            console.log(a);
            c=0;
           // var c;
            a=3;
            b=2;
            console.log(b);
           // function b(){}
           // function d(){}
            console.log(b);
        }
        test(1);
        

全局预编译三步走:

  1. 生成一个GO的对象,Global Object(window就是GO)
  2. 找形参和变量声明,值为undefined
  3. 在函数体里找函数声明,值赋给函数体

例如:

        console.log(a);
        var a=123;
        function a(){
    
    }

预编译:先声明a变量,值为undefined,然后将函数声明赋值给a,到此预编译结束,开始执行,因此console.log显示的是function a(){}

那么问题又来了,是先生成GO还是先生成AO?
想执行全局,当然是先有GO,然后才能有AO,
但是在函数体内预编译时,AO若有该变量,则用AO的,AO没有才用GO

例如:

        console.log(test);
        function test(){
    
    
            console.log(test);
            var test=234;
            console.log(test);
            function test(){
    
    }
        }
        test(1);
        var test=123;
        console.log(test);

先开始GO:
第一二步
GO{
test=undefined;
}
第三步
GO{
test= function test(){};
}

至此全局预编译完成,开始执行
因此 第一个控制台打印为
test =function test(){};

而执行test(1)之前先生成AO
AO开始:
AO{
test:undefined
}

AO{
test= function test(){}
}
此时函数内部预编译完成后等价于:

            function test(){
    
    
            console.log(test);
            test=234;
            console.log(test);
            //function test(){}
        }

然后函数内部开始运行,第二个控制台打印 test= function test(){},然后将234赋值给test,第三个打印234

欢迎大家点赞收藏加关注!!!有不懂的可以随时留言,我们互相探讨

猜你喜欢

转载自blog.csdn.net/weixin_42898315/article/details/111028487
今日推荐