JavaScript中函数内重赋值var变量为何会作用到函数外部?
问题核心原因
你在函数内写的c = 2从来没有创建过函数作用域内的局部变量,本质是顺着作用域链修改了全局作用域下已经存在的变量c,修改结果当然会在函数外部生效。
JS变量赋值的作用域查找规则
JS引擎执行赋值语句时,会严格按照从内到外的顺序沿作用域链查找目标变量:
- 首先检查当前函数作用域内,是否存在通过
var/let/const/function声明的同名变量,如果有,就直接修改这个局部变量,不会影响外层 - 如果当前作用域找不到,就逐层向上跳到外层作用域查找,直到全局作用域
- 非严格模式下,如果全局作用域也找不到同名声明,才会自动在全局创建一个隐式全局变量再赋值;严格模式下这种情况会直接抛出
ReferenceError,不会偷偷创建全局变量
回到你的示例代码,全局作用域一开始就通过var c = 1声明了变量c,函数Fn内部没有任何对c的声明,执行c=2时会直接找到全局的c修改值,不存在“被限制在函数作用域”的可能。
对你的猜想的纠正
你的猜想:当在函数内编写
c = 2语句时,是否是JavaScript引擎自动在函数外部提升声明一个新的var c,先为其赋值undefined,待Fn()调用执行时再将值修改为2?
这个结论是错的,核心原因是你对变量提升的作用范围存在误解:
变量提升只发生在声明所在的当前作用域内,永远不会跨作用域跑到外层去新增声明。
你的代码执行的完整流程没有任何“外部新增var c”的步骤:
- 全局上下文预编译阶段:全局的
var c声明、Fn函数声明被提升到全局作用域顶部,c初始值为undefined - 全局代码逐行执行:运行到
var c = 1时,全局c被赋值为1 - 调用
Fn()进入函数上下文:预编译扫描函数内部,没有找到任何c的声明,因此函数作用域内根本不存在c这个变量绑定 - 函数内执行
c=2:沿作用域链找到全局的c,将其值修改为2 - 函数执行结束弹出调用栈,全局访问
c时拿到的就是修改后的值2
对比参考:如果要让赋值只在函数内生效的写法
只要在函数内部显式声明c,赋值就会被限制在函数作用域内,不会影响全局的c:
var c = 1; function Fn() { // 函数内显式声明局部变量c var c = 2; } Fn(); console.log(c); // 输出1,全局变量没有被修改
内容的提问来源于stack exchange,提问作者user10869882
相关产品推荐
相关产品推荐

