1

函数声明(funDeclaration)

无论在哪儿定义函数,只要是外层函数并且满足不被包裹,就都可以进行全局范围的调用

function foo() { }

在函数体内部的函数声明无法提升到全局,只能提升到函数体内顶部(块级作用域空间)

function test() {
    console.log(1);

    function test2() {
      console.log(2);
    }

  }
  test();  // 1
  test2(); // Uncaught ReferenceError: test2 is not defined

函数体内部执行:

function test() {
   
    test2();
    function test2() {
      console.log(2);
    }
  }
  test(); // 2

在外部要想访问函数内部申明的函数,需要先return出来:

function test() {
    console.log(1);

    function test2() {
      console.log(2);
    }
    return {
      test2:test2
    }
  }
  test().test2(); // 2

函数表达式(funExpression)

函数表达式需要等到表达式赋值 完成 才可以

换言之使用var来声明函数,就会涉及到变量的声明提升,先拿出变量名定义为undefined,再随着逻辑顺序进行赋值先定义,后使用
var foo = function () { }

demo1

    Toast()    // hello world

    showToast(); // shwoToast is not a function

    var showToast = function () {
      console.log('123')
    }
    function Toast() {
      console.log('hello world') 
    }
在这里只需要把showToast 提前就好了

demo2

主流浏览器解析,ie11+

 var sayHello;
    console.log(typeof (sayHey));//=>undefined   
    console.log(typeof (sayHo));//=>undefined
    if (true) {
      function sayHey() {
        console.log("sayHey");
      }
      sayHello = function sayHo() {
        console.log("sayHello");
      }
    } else {
      function sayHey() {
        console.log("sayHey2");
      }
      sayHello = function sayHo() {
        console.log("sayHello2");
      }
    }
    sayHey();// => sayHey   
    sayHello();// => sayHello

在花括号里面声明的函数在进行预解析时只会提升函数名,不会提升函数体,所以不管if条件是否为真,函数体都不会提升,永远是undefined,接下来随着if条件判断进行解析赋值,当然是走ture方法。

ie9,ie10

var sayHello;
    console.log(typeof (sayHey));//=>function    
    console.log(typeof (sayHo));//=>undefined
    if (true) {
        function sayHey() {
            console.log("sayHey");
        }
        sayHello = function sayHo() {
            console.log("sayHello");
    }
    } else {
        function sayHey() {
            console.log("sayHey2");
        }
        sayHello = function sayHo() {
            console.log("sayHello2");
        }
    }    
    sayHey();// => sayHey2    
    sayHello();// => sayHello

在这里的ie将所有的函数声明进行了提升,从而由sayHey2替代了sayHey,函数表达式的在顺着条件判断进行了定义,执行为true的情况,进行赋值解析。

ie8

var sayHello;
    console.log(typeof (sayHey));//=>function    
    console.log(typeof (sayHello));//=>function
    if (true) {
        function sayHey() {
            console.log("sayHey");
        }
        sayHello = function sayHo() {
            console.log("sayHello");
    }
    } else {
        function sayHey() {
            console.log("sayHey2");
        }
        sayHello = function sayHo() {
            console.log("sayHello2");
        }
    }    
    sayHey();// => sayHey2    
    sayHello();// => sayHello

ie8在这里处理的比较奇葩,正常的函数申明提升,但是却也将条件判断为假的情况进行了提升,我们看到typeof (sayHello)=>function

结论

由于函数声明提升的差异,想要在条件判断中定义不同的函数方法,应该采用定义函数表达式的方法,这样就在各个浏览器中拿到相同的函数方法,得到相同的结果。

 var sayHello;
    console.log(typeof (sayHey));//=>undefined    ie8以下解析为function
    console.log(typeof (sayHo));//=>undefined
    if (true) {
      var sayHey =function sayHey() {
        console.log("sayHey");
      }
     
    } else {
      var sayHey =function sayHey() {
        console.log("sayHey2");
      }
     
    }
    sayHey();// => sayHey   
参考

RainBow
1k 声望16 粉丝

一个喜欢唱歌的前端工程师.