console.log("第一次输出a: ", a) //输出 本地a
if (true) {
// 这里js隐式的把function a的定义放到这里来了,此刻这里有一个 块a
a = 1 // 将 块a的值 由函数修改为1
console.log("第二次输出a: ",a) // 此时输出的是 块a的值
function a() {} // 执行到function a的声明处,此时会将if块中的a同步到外部去,也就是把块a赋值给了本地a, 本地a此刻从undefined被修改为了1
a = 2 // 此处修改的是 块a, 块a的值由1修改为2
console.log("第三次输出a: ", a) // 输出块a的值
}
console.log("第四次输出a: ",a) // if执行完毕,没有块了,此时输出的是本地a的值
函数可以被有条件的声明,这意味着,函数声明可以出现在一个 if 语句里。
可以在if语句处打一个断点。当程序执行到if语句时(linenumber 2),本地a的定义是undefined,且不存在块。
当语句执行进入到if时(linenumber4),此时就会产生块,debug停留在a=1;这句时(此时赋值还未进行),块a已经变为了function,说明if块中的函数声明被提升到了所在作用域的顶部。但此时本地a还是undefined:
当debug停留在a=2;这句时(linenumber 7,赋值还未进行),此时块中执行了function a的函数声明,该声明被同步提升到了块外,影响了本地a,本地a此时从undefined变为了1
当debug执行到if块的最后一句console.log时(linenumber8),打印的是块中a的内容(就近原则,或者说块a遮蔽了本地a),所以输出的结果是2。
当debug执行到最后一句console.log时(linenumber 10),此时if语句已经执行完毕,块没有了,所以打印的只能是本地a的内容,本地a的内容此时的值是1
因为这种诡异特性的存在,MDN直接给出了建议:不应该在生产环境代码中使用这种(函数)声明方式 。