JS预编译——函数预编译和全局预编译

本文详细解析JS的预编译过程,包括函数预编译的四部曲和全局预编译机制。通过多个示例展示了预编译期间函数声明的提升以及全局变量的处理方式,阐述了预编译对函数执行的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JS预编译(函数预编译和全局预编译)

一、函数预编译

预编译发生在函数执行前一步

函数预编译四部曲

  1.  创建AO对象(执行期上下文)
  2.  找形参和变量声明,将变量和形参名作为AO 属性名,值为undefined
  3.  将实参值和形参统一
  4.  在函数体里面找函数声明,值赋予函数体

例一:

<script>
    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);
</script>

结果:

预编译过程:(函数马上要执行,但是还没执行)

首先创建AO对象,也就是函数它产生的存储空间库

AO{

}

然后去函数中找形参和变量声明,然后将形参和变量声明值作为AO对象的属性名,值为undefined

AO{

      a:undefined,

      b:undefined

}

再将形参和实参的值统一

AO{

      a:1,

      b:undefined

}

最后在函数体中找函数声明

AO{

      a:1,

      b:undefined,

}

  //因为a 已经有了所以被替换了,但是值要被替换 要被替换成函数体  所以变成以下对象

AO{

      a:function a() {},

      b:undefined,

     d:function d() {}

}

然后函数开始执行

1    function fn(a) {
2        console.log(a);
3        var a = 123;
4        console.log(a);
5        function a() {}
6        console.log(a);
7        var b = function(){}
8        console.log(b);
9        function d() {}
10     }
11    fn(1);

那么首先要执行第2行代码也就是访问AO中的a 所以打印出-:

function a() {}

然后执行第3行 也就是 var a = 123;但是应该执行a=123;因为在预编译的第一步变量a被提前了所以此时打印结果为:

123

然后再执行第5行  function a() {} 因为已经提前执行了,所以此处省略,所以第6行打印的结果为:

123

当执行到第7行时原来的undefined变为 function 

AO{

      a:function a() {},

      b:function(){},

     d:function d() {}

}

所以打印结果为:

function(){}

例二:

 1 function test(a,b) {
 2      console.log(a);
 3       c = 0;
 4       var c;
 5       a = 3;
 6       b = 2;
 7       console.log(b);
 8       function b() {}
 9       function d() {}
 10      console.log(b);
 11   }
 12   test(1);

AO创建的过程:

AO{
    a:undefined,
    b:undefined,
    c:undefined,

}

实参形参统一:

AO{
a:1,
b:2,
c:undefined

}

找函数体:

AO{
a:1,
b:function b(){},
c:undefined,

d:function d(){}
}
然后函数执行:

AO{
a:1,
b:2,
c:0,

d:function d(){}
}

所以结果为:

 

 

例三:

    function test(a,b) {
        console.log(a);
        console.log(b);
        var b = 234;
        console.log(b);
        a = 123;
        console.log(a);
        function a() {}//函数声明
        var a ;
        b = 234;
        var b = function() {} // 函数表达式
        console.log(a);
        console.log(b);
    }
    test(1);

 执行结果

[Function: a]
undefined
234
123
123
[Function: b]

二、全局体系预编译

​ 

如图:如果直接在全局调用a变量会出现undefined

但是如果代码改为:

 则结果如上图;

从而引出全局编译过

  1. 生成一个GO对象,Global Object,即window对象
  2. 找形参和变量声明,将变量和形参名作为GO属性名,值为undefined
  3. 在函数体里面找函数声明,值赋予函数体
 

上图的编译模型如下:

GO{

     b:123

}

 AO{

     a:undefined

}

例一

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

      }
  }
  test(1);
  var test = 123;

GO{

       test:function  test(){}

}

AO{

      test:undefined,

}

AO{

      test:function (){}

}

AO{

      test:234,

}

结果:

[Function: test]
[Function: test]
234

//此时存在一个问题:即GO和AO中都有test ,那么这里到底是打印那个test

答:打印AO的,如果AO没有则取GO的。

 

例二

    var global =100;
    function fn(){
        console.log(global);
    }
    fn();

GO{

     global:undefined,

     fn:function(){}

}

GO{

     global:undefined,

     fn:function(){}

}

AO{

     global:100,因为AO 本身没有global则去在GO中找即

}

例子三

 global =100;
    function fn(){
        console.log(global);
        global =200;
        console.log(global);
        var global  =300;
        console.log(global);
    }
    fn();
    var global;
//先找声明语句var global; 那么此时global:undefined;
GO{
     global:undefined
}
//然后执行global=100
GO{
     global:100
}
//然后函数开始执行执行:虽然没有形参,但它有自己的global
AO{
     global  : undefined
}

AO{
     global  : 200
}
AO{
     global  : 300
}

结果:

undefined
200
300

例子四

 function test() {
        console.log(b);
        if(a){
            var b = 100;
        }
        c=234;
    }
    var a;
    test();
    a=10;
    console.log(c);
//先找声明语句var a; 那么此时a:undefined;
GO{
    a:undefined
}
//然后执行test();由于没有形参和内部函数声明则直接找变量声明
AO{
  //由于a此时为undefined 所以 var b= 100;不会执行当函数执行到c =234时,由于函数内部没有声明语句所以它是全局变量,即window.c
     b:undefined
}

GO{

a:undefined,

c:234

}

然后函数执行完 a=10

GO{

a:10,

c:234

}

结果:

undefined
234

例五

 function bar() {
       return foo;
       foo =10;
       function foo() {

       }
       var foo  =11;
    }

    console.log(bar());

打印结果:

function foo() { }

 

例六

 console.log(bar());
    function bar() {
        foo =10;
        function foo() {

        }
        var foo = 11;
        return foo;
    }

打印结果:11

例七

  a=100;
    function demo(e) {
        function e() {}
        arguments[0] =2;
        console.log(e);
        if(a){
            var b  = 123;
            function c() {}
        }
        var c;
        a=10;
        var a;
        console.log(b);
        f=123;
        console.log(c);
        console.log(a);
    }
    var a;
    demo(1);
    console.log(a);
    console.log(f);
GO{
    a:undefined,
    demo:function(){}
}
GO{
a:100,
demo:function(){}
}
//demo执行
AO{
    e:undefined,
    b:undefined,
    c:undefined,
    a:undefined
}
//形参实参统一
AO{
e:1,
b:undefined,
c:undefined,
a:undefined
}
//在函数体里面找函数声明,值赋予函数体
AO{
e:function e(){},
b:undefined,
c:undefined,
a:undefined
}
//形式实参相映射
AO{
e:2,
b:undefined,
c:undefined,
a:undefined
}
//由于a = undefined 所以var b  = 123; function c() {} 不执行
AO{
e:2,
b:undefined,
c:undefined,
a:10
}
//当执行到        f=123; 时将f 付给windo对象即
GO{
a:100,
demo:function(){},
f:123
}

结果:

2

undefined

undefined

10

100

123

 

预编译会造成的两种提升:

1. 函数声明整体提升

2. 函数声明提升

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值