为什么允许在JavaScript的If语句中重新声明变量
我知道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
}
相关文章