所以我刚刚在javascript项目工作时遇到了一些非常奇怪的事情,这里有一个我很困惑的情况的简单示例:
function doSomething() {
for(var d = 0;d < 10;d++) {
var shouldBePrivate = 5;
}
for(var d = 0;d < 10;d++) {
console.log(shouldBePrivate);
}
}
当你调用doSomething()时,可以在2nd for循环中访问shouldBePrivate变量。
这不应该是不可能的吗?
答案 0 :(得分:5)
javascript中的所有局部变量都有函数作用域而不是块作用域(至少在ECMAScript 2015
之前)。这意味着函数内部声明了变量,可用于整个函数。
您所指的是块范围。不幸的是,Javascript中的noblock范围直到ECMA2015
。从ECMAScript 2015
开始,您可以使用let
声明您的变量,这些变量只能在块中引用,并且一旦您从该块中退出就会死亡。
块范围规则
使用 var
使用var声明的变量没有块范围。块引入的变量的范围限定在包含的函数或脚本中,设置它们的效果会持续超出块本身。换句话说,块语句不引入范围。虽然“独立”块是有效的语法,但您不希望在JavaScript中使用独立块,因为如果您认为它们在C或Java中执行类似此类的操作,则它们不会按照您的想法执行操作。对于
example:
var x = 1;
{
var x = 2;
}
console.log(x); // logs 2
这会记录2,因为块中的var x语句与块之前的var x语句在同一范围内。在C或Java中,等效代码将输出1。
使用let和const
相比之下,使用let和const声明的标识符具有块范围:
let x = 1;
{
let x = 2;
}
console.log(x); // logs 1
The x = 2 is limited in scope to the block in which it was defined.
答案 1 :(得分:2)
你偶然发现了一个叫做吊装的东西。因为所有变量都作用于其包含函数,所以var
语句在内部移动到函数的顶部。
这意味着解释器实际上将运行此代码:
function doSomething() {
var shouldBePrivate;
var d;
for(d = 0;d < 10;d++) {
shouldBePrivate = 5;
}
for(d = 0;d < 10;d++) {
// now it's easy to see why this works
console.log(shouldBePrivate);
}
}
从ES2015开始,您可以使用let
关键字而不是词法作用域的var
- 即在块内限定范围,这意味着let shouldBePrivate = 5;
将不存在于第一个循环之外。
function doSomething() {
for(let d = 0;d < 10;d++) {
let shouldBePrivate = 5;
}
for(let d = 0;d < 10;d++) {
// Reference Error for shouldBePrivate
console.log(shouldBePrivate);
}
}