为什么允许在JavaScript的If语句中重新声明变量

2022-09-24 00:00:00 node.js scope javascript var

我知道if语句不像函数那样有自己的作用域,这意味着它与包含上下文的作用域相同。但如果是这样,为什么允许我再次重新声明相同的变量?

var foo = 123;
if (true) {
    console.log(foo) // 123
    var foo = 456; // Shouldnt it throw an error if refers to same variable?
}
console.log(foo) // 456

解决方案

我们需要了解编译器和Java脚本运行时引擎如何处理和执行代码。

编译器

让我们看看编译器如何看到下面的代码片段并创建适当的作用域。

1. var foo = 123;
2. if (true) {
3.   console.log(foo) // 123
4.   var foo = 456;
5. }
6. console.log(foo) // 456
  1. 第1行上的编译器在第一次遇到foo标识符时将该标识符放入全局作用域。
  2. 在第2行,它编译器创建一个块作用域来保存标识符的引用。
  3. 第3行是执行上下文,因此编译器移到下一行。
  4. 第4行的编译器看到foo标识符,并检查该标识符是否已存在于全局作用域中(注意:var没有块作用域。因此,它在作用域中向上看一个级别,即全局作用域)。此处全局作用域已具有该标识符,因此它转到下一行代码。
  5. 第6行是执行上下文。

Java(JS)引擎

它使用编译器创建的作用域分配和执行代码。

  1. 第1行运行时在作用域中查找标识符foo,因为它赋值为123
  2. 第2行是真实的,因此它进入了块。
  3. 在第3行,它在块作用域中查找标识符foo。由于foo不存在于块作用域中,因此它看起来比全局作用域高一个级别。foo在全局作用域中可用,值为123。因此console.log(foo)123
  4. 第4行:它在块作用域中查找标识符foo。由于foo不存在于块作用域中,因此它看起来比全局作用域高一个级别。foo在全局作用域中可用,因此它将值456重新赋值为foo。现在foo is 456
  5. 第6行。JS引擎在当前作用域中查找foo标识符,当前作用域为全局作用域。foo在全局作用域中可用,值为456

现在,让我们看看问题

为什么允许在JavaScript的If语句中重新声明变量?

var foo = 456;看起来像是重新声明,但实际上并非如此。它使用相同的全局声明的标识符。

在某些情况下,出于readability的目的最好使用这种模式。

function test() {
  var siteId;
   
  if(condition) {
    // more code 100+ lines
    siteId = getId();
  } else {
    var siteId = 1001; // redeclaring here we are communicating the reader for sure we have the `siteId`
  }
   
 // other code

}

相关文章