记一次群里的变量提升问题——非严格模式函数声明没有块级作用域

458 阅读2分钟

image.png

先看两种情况的代码以及输出结果。

第一种

image.png

PS:更新一下函数提升的结果

var a = 1;
{
    console.log(a, window.a); // func, 1
    a = 2;
    console.log(a, window.a); // 2, 1
    function a(){}
    console.log(a, window.a); // 2, 2
    a = 3;
    console.log(a, window.a); // 3, 2
}
console.log(a) // 2

第二种

image.png

两种情况的区别在于函数声明和赋值语句的先后。这段代码还需要区分严格还是非严格模式,不然结果也不一样。

先说非严格模式,也就是上面两种情况。我直接摘取重要的地方写。

// 1 
a = 2 
function a() {
} // [flag]

// 1
function a() {
} // [flag]
a = 2

上面这两个执行到 // 1 的时候,都有一个函数提升,知道这块概念的都能明白。区别在于两个 flag 的位置。

先看 MDN 的说明。所以非严格模式下,块作用域里的函数声明,依旧赋值给 window

image.png

flag 处理解为完成函数声明。

所以在第一个的 flag 处,因为 a = 2 将作用域里的 a 变成了 2,这个时候去完成声明,window.a 就是 2 了。而第二个依旧是函数,所以 window.afunc

至于为什么 a = 3 只在块内部,可以理解为是因为块内部因为声明函数,存在了一个变量 a,这个赋值改的是块内部的变量 a

再来看看严格模式下的结果。

第一种

image.png

第二种

image.png

严格模式下,函数的声明只在块作用域中。

补充一下分析过程吧。当时是在 var a = 1 后面加了 debugger 然后一步一步看变化的,前面都还好,但是一到 flag 处,全局的 a 就变了,就很懵逼。怀疑来怀疑去,只可能是内部在这里做了赋值,然后去搜了一下。结果就是看到上面说的,非严格模式函数声明没有块级作用域。

image.png

自己尝试,然后注意图中的两个变量吧。

image.png

就酱紫,see you next time.