函数的预解析

83 阅读3分钟

函数的预解析

预解析是什么?
在浏览器解析js中的代码之前, 会有一个 预解析阶段。在预解析阶段, 会将var 声明的变量、声明式定义的函数, 提升到
当前作用域的最顶端(提升到代码的最前面) 
注意: 函数调用,执行函数内部代码之前,也会在函数内部进行预解析,函数内部的变量和函数,只会提升到函数内的最前面
  1. 只有var 声明变量和声明式定义的函数才会预解析
     fun()
     var fn = function () {
       console.log('我是fn函数');
     }
     function fun() {
       console.log('我是fun函数');
     }
     fn()
     fn = 100
     fn()
     /* 
    //   预解析分析: 变量提升,函数提升
    //     var fn;
    //     function fun(){
    //       console.log('我是fun函数');
    //     }
    //     fun() // 正常函数调用
    //     fn = function () {
    //       console.log('我是fn函数');
    //     }
    //     fn() // 正常函数调用
    //     fn = 100
    //     fn()   // 报错  此时fn的值是100
    //  */
    var a = b;
    a = 0
    b = 0
    console.log(a);
    console.log(b);
    // /* 
    //   预解析分析: 变量提升
    //     var a;
    //     a = b;  // 此处执行的时候,变量b有声明,报错 b is not defined
    //     a = 0;
    //     b = 0;
    //     console.log(a);
    //     console.log(b);      
    //  */
   console.log( num ); // undefined
   var num = 100;
   console.log( num ); // 100
  // /* 
  //   预解析分析:
  //     代码执行之前,只要发现代码中有var 申明变量,会将var 声明变量提升到最前面
  //     var num;
  //     console.log( num ) // undefined,声明变量没有赋值,变量就是undefined
  //     num = 100
  //     console.log( num ) // 100    
  // */
      fn();
      function fn() {
      console.log('fn')
      }
      fn();
  // /* 
  //   预解析分析:
  //     在代码执行之前,会将声明式定义的函数提升到最前面
  //     function fn() {
  //       console.log( 'fn' )
  //     }
  //     fn();
  //     fn();
  //  */
  1. 赋值式定义的函数不会函数提升预解析,只有可能会变量提升预解析
      fn();
      var fn = function () {
        console.log('fn')
      }
      fn();
  /* 
    预解析分析:
      代码执行之前,发现有var 声明变量,会将变量声明提升到最前面
      var fn;
      fn(); // 此时变量fn中的值undefined,所以此处函数调用报错
      fn = function () {
        console.log('fn')
      }
      fn();
   */
     fun();  
     var fun = 200
     fun() 
     var fun = function(){  
       console.log('我是fn函数');
     }
     fun()
    // /* 
    //   预解析分析:
    //     var fun;
    //     var fun;
    //     fun();// 报错fun is not a function 不再往下运行
    //     fun = 200
    //     fun() 
    //     fun = function(){  
    //       console.log('我是fn函数');
    //     }
    //     fun()    
    //  */
  1. 函数调动的时候,函数内也会预解析,但是会先进行形参赋值,然后预解析
  function fn() {
    console.log(num)
    var num = 100;
    console.log(num)
  }
  fn();
  /* 
    预解析分析:
      fn函数调用,fn函数内部代码预解析
        function fn(){
          // 预解析
          var num;
          console.log(num) // undefined
          num = 100;
          console.log(num)// 100
        }
   */
    function fn(a){
      console.log('我是fn函数');
      a()
      function a(){
        console.log('我是a函数');
      }
    }
    fn(10); //输出:我是fn函数 我是a函数
    //  预解析分析: 函数调动时,函数内部的代码也会有预解析
    //  但是如果函数调用的时候有形参赋值,则会先进行形参赋值,后预解析
    //  fn(10)函数调用,函数内:
    //    a = 10;  // 形参a 是函数内的变量
    //    function a(){
    //      console.log('我是a函数');
    //    }
    //形参变量a里面的值,原来是10,然后定义函数和a同名,所以将变量a中的值覆盖为一个函数了

    // console.log('我是fn函数'); 
    // a();   此时a里面是一个函数,所以正常调用
  1. 函数内的return 不会影响函数内的预解析
     function fn(){
       console.log(num);  
       return; //return关键字只会终断代码的执行,会不影响预解析
       var num = 100
     }
     fn();
    //   预解析分析:
    //     在函数内部,预解析; 函数内的return关键字只会终断代码的执行,会不影响预解析
    //     var num;
    //     console.log(num); // undefined  
    //     return;
    //     num = 100    
  1. 分支结构中的条件和大括号也不会影响预解析(变量提升)
     console.log(num); 
     if(false){
       var num = 100;
     }
    // /* 
    //   预解析分析:
    //     在js条件分支中的预解析(变量提升),不会受到条件判断的影响,不受此处大括号的影响
    //     var num
    //     console.log(num);  // undefined
    //     if(false){
    //       num = 100;
    //     }