美文网首页
js预编译

js预编译

作者: small_Axe | 来源:发表于2021-12-06 18:04 被阅读0次

    JavaScript预编译

    大家都知道JavaScript是解释型语言,既然是解释型语言,就是编译一行,执行一行,先看代码:

    // 1、
    var variable = 1;
    console.log(variable); // 1
    // 2、
    console.log(variable);
    var variable = 1; // undefined
    

    各位前端同学应该都听过变量提升这个词吧,或者在面试的过程中遇到过类似下面这样的笔试题:

    <script>
        a = 100;
    
        function test(e){
          function e() {}
          arguments[0] = 2;
          console.log(e);
          console.log(c);
          if(a){
              var b = 123;
              function c() {}
          }
          var c;
          var a;
          a = arguments[1];
          console.log(a);
          console.log(b);
          f = 456;
          console.log(c);
          console.log(f);
        };
    
        var a;
        test(1,2);
        console.log(a);
        console.log(f);
    </script>
    

    分别打印出什么?因为这个问题是很经典的,而且也是很容易出错的。

    在JavaScript中存在一种预编译的机制, 也就正是因为这个预编译的机制,导致了js中变量声明提升和函数声明提升的一些问题。记住下面这两句话,能解决开发中一部分问题,还有很多问题必须学习预编译才能解决。

    1. 函数声明整体提升
    2. 变量 声明提升(*注意是变量声明)

    这其实也是预编译的两个规则。

    预编译发生在什么时候

    预编译分为全局预编译和局部预编译,全局预编译发生在页面加载完成时执行,而局部预编译发生在函数执行的前一刻。

    预编译阶段发生变量声明和函数声明,没有初始化行为(赋值),匿名函数不参与预编译 。只有在解释执行阶段才会进行变量初始化 。

    js运行三步曲

    1. 语法分析 (通篇扫描看有没有语法错误)
    2. 预编译
    3. 解释执行

    预编译前奏

    imply global 暗示全局变量:即任何变量,如果变量未声明即赋值,此变量就为全局对象所有

    • a = 123;
    • var a = b = 123;

    2.一切声明的全局变量,全是Windows属性。

    • var a = 123;==>window.a=123;
      function Fn() {
        var a1 = b1 = 110;
      };
      Fn();
      console.log(a1); // ReferenceError: a1 is not defined
      console.log(b1); // 110  这里的b1是未经声明的变量,所以是归window所有的。
    

    预编译步骤

    局部预编译(函数执行前)

    • 创建AO(Activation Object)对象(执行期上下文)
    • 查找函数形参及函数内变量声明,形参名及变量名作为AO对象的属性,值为undefined
    • 实参形参相统一,实参值赋给形参
    • 查找函数声明,函数名作为AO对象的属性,值为函数引用

    全局预编译(代码块script执行前)

    • 创建GO对象(Global Object)全局对象。
    • 找变量声明,将变量名作为GO属性名,值为undefined
    • 查找函数声明,作为GO属性,值赋予函数体

    GO对象是全局预编译,所以它优先于AO对象所创建和执行,GO对象其实就是window对象,所以var a = 123; ==> window.a=123;

    实例详解

    我们回头看看本文刚开始的那道笔试题:

      a = 100;
    
      function test(e){
        function e() {}
        arguments[0] = 2;
        console.log(e);
        console.log(c);
        if(a){
            var b = 123;
            function c() {}
        }
        var c;
        var a;
        a = arguments[1];
        console.log(a);
        console.log(b);
        f = 456;
        console.log(c);
        console.log(f);
      };
    
      var a;
      test(1,2);
      console.log(a);
      console.log(f);
    

    我们先看全局GO对象

    // 1. 创建GO对象
    GO = {
    
    }
    // 2.找变量声明,将变量名作为GO属性名,值为undefined
    GO = {
      a: undefined
    }
    // 3.查找函数声明,作为GO属性,值赋予函数体
    GO = {
      a: undefined,
      test: function test() {}
    }
    
    // 4.执行代码块,执行到test(1, 2),生成AO对象:
    GO = {
      a: 100,
      test: function test(1, 2) {...}
    }
    
    
    // 5.创建AO对象(Activation Object)执行期上下文。
    AO = {}
    // 6.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
    AO = {
      e:undefined,
      b:undefined,
      c:undefined,
      a:undefined
    }
    // 7.将实参值和形参统一。
    AO = {
      e:1,
      b:undefined,
      c:undefined,
      a:undefined
    }
    // 8.在函数体里面找函数声明,值赋予函数体。
    AO = {
      e:function e () {}, //值覆盖
      b:undefined,
      c:undefined, // 预编译不管if语句先执行
      a:undefined
    }
    
    // 9.执行函数test, arguments[0]与形参相映射,所以e的值为2,此时AO对象内属性为:
    AO = {
      e:2, //值覆盖
      b:undefined,
      c:undefined, 
      a:undefined
    }
    // 输出e, c分别为: => 2,undefined
    
    // 10. 此时a为undefined,不执行语句。
    
    // 11. arguments[1]的值赋值给a,arguments[1]的值为2,此时a为2,
    AO = {
      e:2, //值覆盖
      b:undefined,
      c:undefined, 
      a: 2
    }
    // 输出a,b的结果分别为:2,undefined;
    
    // 12. f未声明,暗示全局变量,添加到GO
    GO = {
      a: 100,
      test: function test(1, 2) {...},
      f: 456
    }
    
    // 13. 输出c,f,此时AO里面没有f,自动寻找GO里面的f,输出结果为:undefined,456;
    
    // 14. 函数执行结束,回到window对象,执行输出a,f,此时的a,f均为GO对象内的属性,因为window不能访问局部变量,所以输出结果为:100,456;
    
    // 最终输出: 
    // 2,
    // undefined,
    // 2, 
    // undefined,
    // undefined,
    // 456,
    // 100,
    // 456
    

    再看几道例题

    // 1
      a = 12;
      function fn() {
        console.log(a);
        var a = 100;
        console.log(a);
        var a = 200;
      }
      fn();
      console.log(a)
      var a;
    
      // 输出:undefined, 100, 12
    

    分析:
    GO = {
    a: undefined 12,
    fn: funtion() {}
    }
    AO = {
    a: undefined 100  200              
    }

      // 2、
      function fn(a, b) {
        console.log(a); 
        c = 0;
        var c;
        a = 3;
        console.log(a);
        console.log(b)
        b = 2;
        console.log(b);
        function b() {};
        console.log(b); 
      }
      fn(1);
      // 最后输出:1, 3, f b() {}, 2, 2
    

    // 分析
    AO = {
    a: undefined  1   3,
    b: undefined  function b() {}  2,
    c: undefined 0
    }

    相关文章

      网友评论

          本文标题:js预编译

          本文链接:https://www.haomeiwen.com/subject/rhknxrtx.html