为什么JS函数b中给a赋值为10未修改全局变量a的值?
问题原因解释
这个现象本质是函数声明提升规则和作用域查找优先级共同作用的结果,以下是逐段拆解:
首先贴出你给出的原始代码:
var a = 1; function b(){ a = 10; return; function a(){} } // console.log("a equals to ",a); -> 1 b(); // console.log("now a equals to ", a) -> 1
核心逻辑拆解
- 函数预编译阶段的提升逻辑
JS引擎在进入函数b的执行上下文时,会先扫描整个函数内部的所有代码,将所有函数声明提前到当前作用域的最顶部完成初始化,这个规则不受代码位置影响——哪怕函数声明写在return语句之后,也会优先完成提升。
所以在b开始执行第一行代码前,内部已经存在一个本地作用域变量a,初始值就是被提升的function a(){},作用域查找时会优先使用这个本地变量,不会访问全局的a。 - 函数执行阶段的赋值逻辑
执行a = 10时,优先命中了本地作用域的a,所以只是把本地的a赋值为10,完全没有修改全局的a。之后return直接退出函数,后续的函数声明已经在预编译阶段处理完毕,不会再执行。 - 全局变量未被修改
整个b的执行过程都没有触碰全局作用域的a,所以两次打印全局a的结果都是1。
对你提到的其他情况的解释
你提到换成const a = function()的写法放在return之前时,全局变量会被修改为10,原因是:
函数表达式(包括const/let/var声明的函数赋值写法)不会享受函数声明的提升规则,只有当代码执行到声明行时才会初始化本地变量。如果你把const a = function()写在a = 10之后,在执行a = 10时本地作用域还没有创建a变量,作用域查找就会向上找到全局的a,直接修改全局值。
注:如果
const a = function()写在a = 10之前,那么a = 10会触发const常量不可重赋值的报错,不会修改任何值。
对你的困惑的解答
你在b内部打印a得到10是完全正常的:你打印的是b的本地作用域里的a,它已经被赋值为10,只是这个本地变量在函数执行结束后就会被销毁,完全不会影响全局的a,所以外部打印全局a还是初始值1。
内容的提问来源于stack exchange,提问作者Antonios Zaravelas
相关产品推荐
相关产品推荐

