问题描述
我知道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行上的编译器在第一次遇到foo标识符时将该标识符放入全局作用域。
- 在第2行,它编译器创建一个块作用域来保存标识符的引用。
- 第3行是执行上下文,因此编译器移到下一行。
- 第4行的编译器看到foo标识符,并检查该标识符是否已存在于全局作用域中(注意:var没有块作用域。因此,它在作用域中向上看一个级别,即全局作用域)。此处全局作用域已具有该标识符,因此它转到下一行代码。
- 第6行是执行上下文。
Java(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 }