JS代码预编译

JS代码执行过程

  1. 语法检查

  • 当代码语法出现错误,比如英文逗号(,)写成了中文逗号(,),英文冒号(:)写成了中文冒号(:)等等 。此时 ,控制台就会报错语法错误。
  1. 预编译

  • 预编译有全局(GO)和局部(AO)预编译,此时会分别创建一个对象。全局预编译发生在HTML执行完后,才会开始编译,而局部预编译是发生在函数执行前。
  1. 了解函数的类型

    • 函数声明式 function fun(){}
    • 函数表达式 var fn=function(){}
    • 通过 new Function()构造的函数对象
  2. 了解变量提升

    • 函数声明式,它会自动提升自己的位置,处在当前作用域下的最前面(等下上代码演示)。
    • 函数表达式 ,比如var fun2=function(){}不会将fun2=function(){}提到最前面 ,只是会将 fun2这个变量放在最前面。我们都知道var 可以提升变量,但是它的值在最作用域最前面下是undefined,而不是function(){}这个匿名函数,只有代码执行到这句话,此时fun2才会等于function(){}这个匿名函数
  • 全局变量(定义在window下的var变量)和函数声明式,会先在window下最前面,值为undefined。而局部作用域下的var声明的变量和函数声明式,也会和window下声明的一样,只不过局部函数,会比window多一步操作,将传进来的实参和形参统一。
  • 在AO和GO下所有函数声明式的属性名(key)作为AO或GO属性,值(value)为函数的内容。
  1. 代码执行

  • 做完上述预编译操作后,代码就将执行,直到结束。
  1. 代码示例

  • GO变量提升

    console.log(v1);
    let v1 = 'hello1';
    ---------------------------------
    console.log(v2);
    const v2 = 'hello2';
    ---------------------------------
    console.log(v3);
    const v2 = 'hello3';
    console.log(v3)
    ---------------------------------
    console.log(fn1);
    console.log(fn2);
    function fn1(){
    console.log('我是fn1');
    }
    var fn2=function (){
    console.log('我是fn2');
    }
    console.log(fn2);
    
    1. v1输出 Uncaught ReferenceError: Cannot access ‘v1’ before initialization,可见let不可以提升变量
    2. v2输出 Uncaught ReferenceError: Cannot access ‘v2’ before initialization,可见const也不能提升变量
    3. v3先输出undefined,后输出hello3。相当于var v3;v3='hello3'
    4. 输出fn1,可见打印处了 f fn1(){ console.log('我是fn1'); }
    5. 输出fn2,可见先打印了undefined,虽然fn2提升了变量,但是并没有赋值,默认值为undefined,只有执行完这fn2=function(){}这一行,然后才会打印 f (){ console.log('我是fn2'); }
  • AO变量提升

        function fn3(a) {
        console.log(a);//log1
        var a = 1;
        console.log(a);//log2 
        console.log(fn5);//log3
        function a() {
          console.log('我是a');
        }
        console.log(a);//log4
        var fn5 = function () {
          console.log('我是fn5');
        }
        a = 10;
        console.log(fn5);//log5
        console.log(a);//log6
      }
      fn3(3);
    
    1. log1这行先输出ƒ a() { console.log('我是a'); }
    2. log2这一行输出1
    3. log3这一行输出undefined
    4. log4这一行输出1
    5. log5这一行输出ƒ () { console.log('我是fn5'); }
    6. log6这一行输出10
    • 此时的你是不是心态爆炸?你是不是觉得log1这一行应该输出1,而不是ƒ a() { console.log('我是a'); }?log4这一行应该输出ƒ a() { console.log('我是a'); },而不是1?我相信大家对于log3和log5这两行应该是懂了的。我知道大家的疑问,毕竟作者原先我就这么和大家认为的一样,避免大家的苦恼,就让我再给大家捋一遍。
    • 首先,AO会创建一个对象{},然后将可以提升的变量名放在这个对象中,作为属性。因此首先会有{ a:undefined, fn5:undefined }
    • 随后,将传入的实参与形参统一,AO对象会有{a:1,fn5:undefined}
    • 最后,会将函数的内容作为属性的值,会将实参传入的值进行覆盖,因此AO对象会有{a:function(console.log(‘我是a’)),fn5:undefined}。这是预编译做的所有事请,然后就执行代码
    • 执行的代码就相当于
     function fn3(a) {
     a=function(){
     console.log('我是a')
     }
      var fn5;
      console.log(a);//ƒ a() {console.log('我是a');}
      a = 1;
      console.log(a);//1
      console.log(fn5);//undefined
      console.log(a);//1
      fn5 = function () {
        console.log('我是fn5');
      }
      a = 10;
      console.log(fn5);//ƒ () {console.log('我是fn5');}
      console.log(a);//10
    }
    fn3(3);
    

    总结

    代码执行就相当于就我写的实例最后的转换。并且,我们要知道只有var声明的变量,以及函数声明式可以提升代码的位置。但是用了var 声明的变量,提升到作用域的最前面,值为undefined,只有函数声明式,才可以输出它自身。

    结束语

    如果本文对大家有所帮助,不防给个赞,来个收藏,并且评论评论,给他人带来更大的动力。

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值