js函数提升问题?

foo();
if (true) {
  function foo() {
    console.log('1111');
  }
} else {
    function foo() {
      console.log('22222');
  }
}

在我理解之中,函数提升应该会忽视if和else的大括号,然后第二个foo覆盖第一个foo,最后打印222的么?
为什么报错了

阅读 4.1k
6 个回答

ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明
但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

foo();
if (true) {
  function foo() {
    console.log('1111');
  }
} else {
    function foo() {
      console.log('22222');
  }
}

你的代码如果在es5的环境下运行,就是你说的情况,但是在es6浏览器中为了兼容也做了如下如下规定(只在es6浏览器中)

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部

所以浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量
因此你的代码相当于

foo();
var foo = undefined
if (true) {
  function foo() {
    console.log('1111');
  }
} else {
    function foo() {
      console.log('22222');
  }
}

应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句

这是因为:条件式函数声明跟函数表达式的处理方式一样,所以,条件式函数声明丧失了函数声明提升的特性。

昨天刚好在书上又看到了类似的解释。
通过function xxx() {}定义函数被称之为‘函数声明语句’,ECMAScript规范规定,‘函数声明语句’只能出现在全局代码里或者其他函数体内,但不允许出现在循环,条件判断,try/catch等语句中。但这只是规范,每个浏览器厂商的具体实现会有差异。
var xxx = function() {}这种形式定义函数被称之为‘函数定义表达式’,‘函数定义表达式’没有任何限制,他可以出现在代码的任何地方。

clipboard.png
我试了一下,没报错,看一下你的错误信息

js执行时先创建一个上下文,然后查找其中的变量,创建变量,初始化,执行代码,由于函数在if...else中,初始化时并不会去if ... else中查找

在ES6之前,只有Global Scope Function Scope
原因是在ES6引入了Block Scope

你运行下 下面代码就很清楚了

        console.log(foo) // cause of Block Scope
        {
            console.log(foo) // function hoisting
            function foo() {}
        }
        console.log(foo) // function can create global properties
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题