为何带if块的JS重复变量声明报错?同作用域重复var声明却合法
为什么包含if块的代码会触发重复声明错误?
这个问题的核心是ES6引入块级作用域后,函数声明在块内的特殊处理规则,和传统函数/全局作用域的var声明规则差异很大,咱们一步步拆解清楚:
1. 先看函数/全局作用域的声明逻辑(代码片段1的情况)
在ES5及更早的环境中,JS只有函数作用域和全局作用域,没有块级作用域。这种场景下:
- 函数声明和
var声明都会被提升到作用域最顶部,而且完全允许同一标识符的重复声明; - 函数声明的优先级比
var更高,所以代码片段1的实际执行顺序是这样的:
整个过程不会报错,因为函数/全局作用域对重复声明是宽容的,只会用后续的赋值覆盖之前的绑定。// 提升阶段:先处理函数声明,再处理var声明(重复声明无影响) function a(){}; var a; var a; // 执行阶段:依次赋值 console.log(a) // 此时a是函数本身,输出ƒ a(){} a = 1; a = 10; console.log(a) // 最终a被覆盖为10
2. 块级作用域中函数声明的新规则(代码片段2的情况)
ES6新增了块级作用域(if、for、while等代码块都属于块级作用域),同时对块内的函数声明做了严格规范:
- 块内的函数声明会被提升到块的顶部,但它会被当作块级绑定(行为类似
let/const),这意味着:- 这个绑定只在当前块内有效;
- 同一块内不允许同一标识符的任何形式重复声明——哪怕是用
var也不行。
咱们拆解代码片段2的执行逻辑:
var a = 1; // 全局作用域的var绑定 if(true){ // 提升阶段:块内先创建了块级绑定的`a`(来自function a(){}) function a(){}; // 这里的var a =10会被提升到块顶部,但此时块内已经存在`a`的块级绑定 // 同一块级作用域不允许重复声明同一标识符,直接触发语法错误 var a = 10; } console.log(a)
所以代码还没走到console.log就抛出了Identifier 'a' has already been declared的错误——本质是块内的函数声明已经占用了a这个标识符的块级绑定,后续的var a试图重复声明,直接违反了块级作用域的规则。
一句话总结
- 在函数/全局作用域中,
var和函数声明的重复声明是允许的,重复只会覆盖之前的绑定; - 在块级作用域中,函数声明会被处理为类似
let的块级绑定,同一块内不允许任何形式的重复声明(包括var),因此触发语法错误。
内容的提问来源于stack exchange,提问作者venkata




