关于JavaScript同文件中块级作用域内函数声明未被后续同名函数覆盖的原因咨询
关于JavaScript同文件中块级作用域内函数声明未被后续同名函数覆盖的原因咨询
你这次遇到的现象确实是个容易踩的JS细节坑,先把你最后那段关键测试代码清晰列出来,方便咱们拆解:
{ function testing() { console.log("does it show in the console"); } } testing() setTimeout(()=> testing(), 3000) function testing() { console.log("this will override it"); } testing()
按照你之前的经验,原本以为后面的全局testing函数声明会覆盖前面块内的,结果三次输出全是块内函数的内容——这其实是非严格模式下块级函数声明的特殊提升+执行时序规则在搞鬼,咱们一步步捋清楚:
1. 先看执行前的「提升」隐藏操作
JS引擎在真正执行代码前,会先做「提升(Hoisting)」处理,这一步是后台偷偷完成的:
- 对于你写在块外面的全局函数声明:会直接把整个函数定义提升到全局作用域的最顶部,此时全局变量
testing指向这个输出“override”的函数。 - 对于你写在
{}里的非严格模式块级函数声明:引擎会先在全局作用域创建一个名为testing的变量,但初始值是undefined;而这个函数的实际定义只会提升到块的顶部,不会直接到全局。
2. 按执行顺序看变量的变化
提升完成后,代码开始从上到下执行,这里的关键时序是:
- 执行块
{ ... }:非严格模式下的特殊规则生效——块内的testing函数会被赋值给全局的testing变量。这一步直接把全局testing从之前指向的“override”函数,替换成了块内的“does it show...”函数。 - 执行第一个
testing():此时全局testing已经被块内函数覆盖,所以输出“does it show in the console”。 - 执行
setTimeout:定时器回调会在3秒后执行,但此时全局testing的值已经是块内函数,所以3秒后调用的还是它。 - 跳过后面的全局函数声明:划重点!这个函数声明在提升阶段已经处理过了,执行阶段不会再重新赋值
testing变量。所以这行代码在执行时,完全不会改动testing的指向。 - 执行最后一个
testing():全局testing依然指向块内函数,输出同样内容。
验证:开启严格模式试试
如果你在代码最顶部加上'use strict';开启严格模式,块级函数的行为就会符合你更直觉的预期:块内的testing函数只会被限制在块内部,不会污染全局作用域。此时执行代码,三次输出都会是后面全局函数的“this will override it”——因为严格模式下,块级函数不会跨块提升和赋值,完全符合你最初的预期。
这次的核心收获
- 非严格模式下的块级函数是个“历史遗留特例”,提升阶段占坑、执行阶段赋值的逻辑很反直觉;
- 全局函数声明的提升是一次性的,执行阶段不会重复覆盖变量。
建议日常写JS时尽量开启严格模式,能大幅减少这种“意外”的特殊行为,让代码逻辑更可控~
内容来源于stack exchange
相关产品推荐
相关产品推荐

