You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

为何带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新增了块级作用域(ifforwhile等代码块都属于块级作用域),同时对块内的函数声明做了严格规范:

  • 块内的函数声明会被提升到块的顶部,但它会被当作块级绑定(行为类似let/const),这意味着:
    1. 这个绑定只在当前块内有效;
    2. 同一块内不允许同一标识符的任何形式重复声明——哪怕是用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

火山引擎 最新活动