Javascript块级域内的函数声明提高

主题

昨天个人一个技术交流群里发了一段代码,涉及的是变量和函数的声明提高,执行结果很是让人迷惑,你们讨论许久,仍是有地方解释不清楚,到最后,仍是发布到stack overflow,经过大佬解惑才弄明白,这里我再整理一下。javascript

个人思路

逐个解析一下讨论到的案例:html

没有特别说明的,运行环境就是是chrome77。
var a
  if(true) {
    a = 5
    function a() {}
    a = 0
    console.log(a)
  }

  console.log(a)

先整理一下个人思路:java

  • 首先,全局有一个变量a声明;
  • 而后,有一个if语句块,是一个块级做用域;
  • 块级做用域里面有变量a的赋值,还声明了一个函数a

按照声明提高原则,函数a声明会被提高,这里没有使用letconst,因此我按ES5以前的声明提高规则去分析的。es6

没有块级做用域,提高到全局,并且函数声明优先于变量声明,因此会覆盖变量a的声明。web

那么答案是:chrome

0
0

很遗憾,这个答案是错的,至少现代浏览器是错的(我后来在IE的模拟环境运行,确实是这个结果)。浏览器

如今,公布一下正确答案函数

0
5

这个答案很是让人疑惑不解:code

  • 第一个输出0,好理解
  • 第二个输出5,究竟是怎么回事?htm

    • 若是理解成:let a = function(){},那么a=5是暂时性死区;
    • 若是理解成:var a = function(){},那么会和上面同样,输出0 0

大佬的解析

先看看代码运行解析[引用1],咱们能够把代码运行当作这样:

var a¹;
 if (true) {
   function a²() {} // hoisted
   a² = 5;
   a¹ = a²; // at the location of the declaration, the variable leaves the block      
   a² = 0;
  console.log(a²)
}
console.log(a¹);

解释一下:

  • 全局的变量a声明,这里没有问题。
  • 重点1,块级域的函数a声明提高,提高到块级域顶部
  • 重点2a=5,这里赋值的对象是本地的函数a,覆盖了。
  • 重点中的重点,执行到函数a声明处,本地的变量a覆盖了全局的变量a。按照[引用2]解释,这里也是提高,也就是说函数a声明提高了两次。到这里疑惑终于解开了!

总结

这里要说明两点:

  • 块级做用域{}内的函数声明,在ES5中是非法的,在ES6中并无严格规定(考虑到向下兼容性,参考阮老师的ES6入门),也就是这块依赖于实现[引用3]。
  • 在项目里面,不要在块级做用域{}内声明函数,要在全局做用域或者函数做用域的顶层声明函数。

引用参考

  1. [confused about function declaration in { }

](https://stackoverflow.com/que...

  1. [What are the precise semantics of block-level functions in ES6?

](https://stackoverflow.com/que...

  1. web legacy compatibility semantics
相关文章
相关标签/搜索