块作用域下的函数提升和变量提升

202 阅读3分钟

前言

几天在网上看到一个很有意思题!

这个题的第一直觉很简单但是打印的结果是这样的

var a = 10
console.log(window.a === a) //true
{
console.log(window.a === a) //false
a = 99
function a() {}
console.log(window.a === a) //true
a = 30 
console.log(window.a === a) //false
 } 
 console.log(window.a === a) //true

结果可能和你预料的不一样。。。。

按照平常的逻辑应该是这样的

  • 在块作用域内,函数提升到块作用域的顶部。这个时候window.a 为 10 。a 为一个函数 。块中第一个为false
  • a被重新赋值为 99 这个时候下一个返回了true 打印window.a = 99,a = 99,这个地方显然是 a = 99同时将window下的a也给赋值了。
  • 向下执行a = 30 。按照上述的逻辑这个时候window下的a应该也被修改。但是此时打印了false。window.a = 99; a = 30;
  • 跳出块。执行后返回true。此时window.a = 99 ; a = 99

这个时候产生了疑问。(不在说我分析的过程了,直接说结果把)发现在块作用域下的函数提升和变量提升是不同的。我去重新看了阮一峰老师的块级作用域发现有以下一段话

根据这段话有以下总结

  • 块级作用域下的函数声明会提升到块的顶部
  • 同时在全局作用域下定义一个同名变量(若全局下有相同变量则为此变量。若无为undefined)
  • 这个块外的全局同名变量的赋值时机是执行完块内那行函数声明语句后才赋值(这个就相当于var a = {....有关代码} 所以在执行到函数的声明时 函数声明就等价为 a = (块级作用域下的a的值) 同时将值赋给全局同名变量 )

根据上述总结重新对代码进行分析

  • 在块级作用域内函数提升(但类似var函数声明)此时全局下的 a 为 10 . 块下的a为函数(提升)。
  • 向下执行 a = 99 .此时块下a = 99 .全局 10
  • 执行到函数声明。对全局 a 进行赋值 。此时块下的 a 为 99。全局下 a 此时进行赋值为 99 .(在之后块内不会对全局的a进行影响)
  • 向下执行a = 30。 块下30 .全局 99。
  • 跳出块 。全局下的a为99 .

根据上面的分析可以轻松得到打印的结果了(同学们可以把函数声明的位置进行调整来验证正确性)

严格模式 vs 非严格模式

上述的操作都是在非严格模式下进行的。使用严格模式结果如下

可以看到在严格模式下在全局作用域内的 a 并没有影响。非严格模式下块作用域内的函数提升部分特性失效。即只在块作用域内提升,不会被当做var变量。

不得不说js很有趣。但是总的来说是遵循一套规则的。