函数申明提升的问题,求大神解答!!!
代码:
foo();//TypeError: foo is not a function
var a = true;
if(a){
    function foo(){console.log('a');}
} else {
    function foo(){console.log('b');}
}
上面的代码foo();运行的时候会提示TypeError: foo is not a function。这是我不能理解的地方。
按照我的理解:函数申明会提升到所在作用域的顶部,因此这里的foo()函数的申明会出现在foo();语句的上面,同时下面的一个foo函数申明会覆盖上面一个foo函数申明,所以代码运行应该会输出“b“。但是实际与我的理解并不符合。求大神解答!

解决方案 »

  1.   

    能不能这样定义:
    function foo(){
      if(a){
        console.log('a');
      }else{
        console.log('b');
      }
    }
      

  2.   

    函数申明会提升到所在作用域的顶部是没有错。关键是要明白函数所在的是哪个作用域?
    在es5(也就是ie10以前)中,没有块作用域,两个foo()函数都在全局作用域中,就是按照你理解的会输出“b“。
    但是到了es6(也就是ie11或者其它现代浏览器)中,开始有块作用域了,这样两个foo()函数就分别在两个块作用域中,申明提升也只是提升到块作用域的顶部,你在全局作用域中调用foo()函数当然是未定义。你在if和else后面不写{},就没有块作用域了,两个foo()函数又都在全局作用域中,就是按照你理解的了。
    foo();
    var a = true;
    if(a)
        function foo(){console.log('a');}
    else
        function foo(){console.log('b');}
      

  3.   

    @天际的海浪:块级作用域不是在使用let或const的时候才有的吗?这里没有用到这两个关键字怎么会有块级作用域呢?退一步说,就算这里{}是块级作用域,无法访问foo函数,那也应该是报referenceError,而不是报TypeError呀。TypeError说明变量foo被申明,但是不是函数类型。
      

  4.   

    这是mdn上的说明
      

  5.   

    以前没太注意,这还真是奇怪,给我的感觉是,在Chrome里,
    function foo(){}是在代码执行前先声明了一个var作用域的foo变量(这时foo没有赋值),但是声明提升却是在块作用域内提升,这样又声明了一个同名的let块作用域的foo变量。这时同时存在var作用域的foo变量和let块作用域的foo变量。
    当真正执行到function foo(){}的时候才对var作用域的foo变量重新赋值。
      

  6.   


    console.log("foo" in window);//输出true
    console.log(foo); //输出undefined
    foo=1;
    console.log(foo);//输出1
    if(1){
    console.log(window.foo,foo);//输出 1 和 foo(){console.log('a');}
    function foo(){console.log('a');}
    console.log(window.foo,foo);//输出 foo(){console.log('a');} 和 foo(){console.log('a');}
    }
    if(1){
    console.log(window.foo,foo);//输出 foo(){console.log('a');} 和 foo(){console.log('b');}
        function foo(){console.log('b');}
    }
    console.log(foo);//输出 foo(){console.log('b');}