为啥在 JavaScript 的 IF 语句中允许重新声明变量

Posted

技术标签:

【中文标题】为啥在 JavaScript 的 IF 语句中允许重新声明变量【英文标题】:Why redeclaring a variable is allowed in an IF statement in JavaScript为什么在 JavaScript 的 IF 语句中允许重新声明变量 【发布时间】:2020-04-14 23:19:39 【问题描述】:

我知道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

【问题讨论】:

两者都被提升并被识别为相同。 使用 var - letconst 的众多陷阱之一会在这里抛出错误,但 var 会将两者提升到同一个声明 通过查看控制台日志的输出,这对我来说似乎是一个好问题,如果它是作用域的,我期待第一个日志未定义,第二个日志为 123,好问题。 var 确实有范围,只是它的功能范围。规范中没有错误的原因可能是由于没有意外创建全局。这样做的好处是,您不必在函数顶部声明所有变量。 @Keith 很难将其称为“优势” - var 的这种行为更经常导致程序员试图在较低范围内声明和使用局部变量,然后意外地提升了变量另一个在更高范围内,然后他们修改了那个 - 因此为什么以这种方式(或根本不使用)使用var 是不好的做法 【参考方案1】:

我们需要了解编译器和 javascript 运行时引擎是如何处理和执行代码的。

编译器

让我们看看编译器如何看到下面的代码 sn-p 并创建适当的范围。

1. var foo = 123;
2. if (true) 
3.   console.log(foo) // 123
4.   var foo = 456;
5. 
6. console.log(foo) // 456
    在第 1 行编译器将 foo 标识符放在全局范围内,因为它第一次遇到该标识符。 在第 2 行,编译器创建了一个块作用域来保存标识符的引用。 第 3 行是执行上下文,因此编译器移至下一行。 在第 4 行编译器看到 foo 标识符并检查标识符是否已存在于全局范围内(注意:var 不具有块范围。因此它在范围内向上查找一级,即是全局范围)。这里全局作用域已经有了标识符,所以它转到下一行代码。 第 6 行是执行上下文。

Javascript(JS) 引擎

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

    第 1 行运行时在范围内查找标识符 foo,因为它存在它分配值 123 第 2 行是真实的所以,它进入了块。 在第 3 行,它在块范围内查找标识符 foo。由于foo 不存在于块作用域中,它看起来比全局作用域高一级。 foo 在全局范围内可用,值为123。所以console.log(foo)123 在第 4 行:它在块范围内查找标识符 foo。由于foo 不存在于块作用域中,它看起来比全局作用域高一级。 foo 在全局范围内可用,因此它将值 456 重新分配给 foo。现在foo is 456。 在第 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


【讨论】:

以上是关于为啥在 JavaScript 的 IF 语句中允许重新声明变量的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 python 切片中允许非整数内置类型?

主键中允许 NULL - 为啥以及在哪个 DBMS 中?

为啥Java中允许受保护的静态? [关闭]

如何在 JavaScript 文件中允许空格?

为啥是 ”。” Access中的查询字段名称中允许但表字段名称中不允许?

javascript 变量中允许的最大整数是多少? [复制]