Code前端首页关于Code前端联系我们

预编译 JavaScript

terry 2年前 (2023-09-08) 阅读数 169 #Vue
  • 预编译的 JavaScript

    JavaScript运行三部曲

    1. 语法分析:首先扫描整个代码,看看是否有语法错误
    2. 预编译(执行前一刻):变量和函数声明的提升
    3. 执行:逐行执行

    预编译

    1. 在当前作用域内,在运行 JS 代码之前,浏览器首先默认声明或定义所有带有 var 和 function
    2. var变量声明只会声明,不会定义,且值未定义
    3. 函数声明声明、定义和分配函数体

    全局预编译

    1. 创建全局对象
    2. 找到全局中的变量声明,将该变量声明为全局对象的属性名,并将值赋给undefined
    3. 在全局中找到函数声明,将函数名作为全局对象的属性名,并赋值给函数体
    函数中的预编译

    1. 创建AO对象(执行上下文)
    2. 找到形参,并使用形参作为AO属性名称;如果存在实数参数,则分配实数参数;否则,分配值 undefined
    3. 找到变量声明,将变量作为AO属性名,并赋值undefined
    4. 找到函数声明,将函数名作为AO属性名,将函数体与
    5. 匹配

    块范围内的预编译

    1. var 变量声明不变
    2. function 函数声明将提升到全局或函数作用域的头部,类似于var
    3. 同时函数的函数声明会提升到块级作用域的头部
    if(false) {
      function f() {}
    }
    //等价于
    var f;//var f= undefined;全局作用域
    if(false) {
      function f() {}
    }
     

    预编译案例

    变量与函数

    同名

    当变量与函数同名时,无论哪个在先,只保留函数的值,因此函数声明的优先级更高

    console.log(b);
    function b() {
      console.log('bbb');
    }
    var b = 2;
    //解析过程
    //预编译
    function b() {console.log('bbb');}
    var b;
    //逐行执行
    console.log(b);//[Function: b]
    b = 2;
     
    console.log(a);
    var a = 1;
    function a() {
      console.log(2);
    }
    console.log(a);
    var a = 3;
    console.log(a);
    function a() {
      console.log(4);
    }
    //解析过程
    //预编译
    var a;
    function a() {console.log(2);}
    function a() {console.log(4);}
    //逐行执行
    console.log(a);//function a() {console.log(4);}
    a = 1;
    console.log(a);//1
    a = 3;
    console.log(a);//3
     
    函数中的预编译

    函数中的预编译只有在函数执行前一刻才会被预编译

    var a = 10;
    function f1() {
      var b = 2 * a;
      var a = 20;
      var c = a + 1;
      console.log(b);
      console.log(c);
    };
    f1();
    //解析过程
    //预编译
    var a;
    function f1() {...}
    //逐行执行
    a = 10;
    f1();
      //函数中的预编译
      var b;
      var a;
      var c;
      //函数中的逐行执行
      b = 2 * a;//2 * undefined
      a = 20;
      c = a + 1;
      console.log(b);//NaN
      console.log(c);//21
     

    函数表达式的预编译
    console.log(fn);
    var fn = function() {
      console.log('ok');
    };
    console.log(fn);
    //解析过程
    //预编译
    var fn;
    //逐行执行
    console.log(fn);//undefined
    fn = function() {console.log('ok');};
    console.log(fn);//[Function: fn]
     

    传递函数参数的预编译

    函数中的形参是函数中声明的变量

    function fun(n) {
      console.log(n);
      var n = 456;
      console.log(n);
    }
    var n = 123;
    fun(n);
    //解析过程
    //预编译
    function fun(n) {}
    var n;
    //逐行执行
    n = 123;
    fun(n);
      //函数中的预编译
      var n = 123;//实参给形参赋值,函数中已经声明变量n了,后面就不需要重新声明了
      //函数中的逐行执行
      console.log(n);//123
      n = 456;
      console.log(n);//456
     

    立即预编译功能

    立即执行的函数不会被预编译。其余与正常功能相同。当代码在这个位置逐行执行时,定义和执行一起完成了

    (function(num) {
      console.log(num);
      console.log(n);
    })(100);
    var n = 10;
    //解析过程
    //预编译
    var n;
    //逐行执行
    (function(num) {...})(100);//函数执行
      //立即执行函数中的预编译
      var num = 100;//实参赋值给形参
      //立即执行函数中的逐行执行
      console.log(num);//100
      console.log(n);//undefined
      n = 10;
     

    预编译函数中的 return

    函数中返回后的代码不会被执行,而是会被预编译

    function fn() {
      console.log(num);
      return num;
      var num = 100;
    }
    fn();
    //解析过程
    //预编译
    function fn() {...}
    //逐行执行
    f();
      //函数中的预编译
      var num;//return后面的代码不会执行,但会预编译
      //函数中的逐行执行
      console.log(num);//undefined
      return num;
     

    if 块中的预编译

    • 不管if判断是否成立,if都会进行预编译;如果语句为真,则执行 if 中的代码块;否则,if中的代码只会被预编译,不会被执行。
    • 我们按照ES6标准开始(仅适用于ES6浏览器实现):
    1. 允许在块级作用域中声明函数(应避免函数声明,可以写成函数表达式的形式)
    2. 函数声明与var类似,即会提升到全局或函数作用域的头部
    3. 同时,函数声明也会被提升到块级范围的头部,即它所在的位置
    //ES6环境的浏览器
    (function() {
      if(false) {
        function f() {
          console.log('ok');
        }
      }
      f();
    }());
    //会报错,实际运行的是以下代码
    (function() {
      var f;//var f = undefined
      if(false) {
        //块级作用域中函数的声明会提升到函数作用域的头部
        function f() {
          console.log('ok');
        }
      }
      f();
    }());
     
    //if判断为假
    console.log(num);
    console.log(f);
    if(false) {
      var num = 100;
      function f() {
        console.log(123);
      }
    }
    console.log(f);
    console.log(num);
    //解析过程
    //预编译
    var num;
    //块级作用域中函数的声明会提升到全局作用域的头部
    var f;//块级作用域中函数的预编译类似于var,先声明后赋值
    //逐行执行
    console.log(num);//undefined
    console.log(f);//undefined
    //由于if判断为假所以if代码块中的代码不执行
    console.log(f);//undefined
    console.log(num);//undefined
     
    //if判断为真
    console.log(num);
    console.log(f);
    if(true) {
      var num = 100;
      function f() {
        console.log(123);
      }
    }
    console.log(f);
    console.log(num);
    //解析过程
    //预编译
    var num;
    //块级作用域中函数的声明会提升到全局作用域的头部
    var f;//块级作用域中函数的预编译类似于var,先声明后赋值
    //逐行执行
    console.log(num);//undefined
    console.log(f);//undefined
    //if判断条件为真,执行if代码块中的代码
    num = 100;
    f = function() {console.log(123);}
    console.log(f);//[Function: f]
    console.log(num);//100
     

    if代码块中函数声明的作用域不同

    console.log(a);
    var a = 0;
    if(true) {
      console.log(a);
      a = 1;
      console.log(a);//1
      function a() {}
      a = 21;
      console.log(a);
    }
    console.log(a);
    //解析过程
    //预编译
    var a;
    //逐行执行
    console.log(a);//undefined
    a = 0;
      //if判断为真
      function a() {}//预编译,函数声明会提升到块级作用域的头部
      console.log(a);//[Function: a]
      a = 1;//改变全局变量的值
      console.log(a);//1
      //函数名和全局变量名同名
      function a() {}//函数后面是另一个作用域,函数上面是全局作用域,后边是局部作用域
      a = 21;//局部作用域中的值
      console.log(a);//21
    console.log(a);//1
     
  • 版权声明

    本文仅代表作者观点,不代表Code前端网立场。
    本文系作者Code前端网发表,如需转载,请注明页面地址。

    发表评论:

    ◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

    热门