在JavaScript中,当一个局部变量被提升时,它甚至在声明之前就已经在作用域中了吗

In JavaScript, when a local variable is hoisted, is it in scope even before it is declared?

本文关键字:声明 作用域 JavaScript 局部变量 一个      更新时间:2023-09-26

在《JavaScript忍者的秘密》一书中,第43-46页,它有一些代码,比如:

function assert(flag, msg) {
    if (!flag) {
        console.log("Assertion failed for: " + msg);
    }
}
function outer() {
    var a = 1;
    function inner() { }
    assert(typeof b === "number", "b is in scope");
    var b = 1;
}
outer();

结论是,由于断言失败,"b在声明之前还不在范围内"。但我认为情况并非如此,因为首先,b可能已经有了一个本地作用域,但它还不是一个"数字"。b实际上已经是局部作用域b,并且将遮蔽任何全局b

例如:

var b = 123;
function foo() {
    b = 456;
    var b = 789;
}
foo();
console.log(b);   // prints out 123

因为它打印出123,所以我们可以看到,当执行行b = 456;时,b已经是本地作用域b。(即使在赋值之前它还未初始化)。

此外,我们可以将其打印出来,而不是分配给b:

var b = 123;
function foo() {
    console.log(b);  // prints out undefined
    var b = 789;
}
foo();
console.log(b);     // prints out 123

因此,我们可以再次看到,第一次打印出来的不是123,而是undefined,这意味着b是一个局部范围b,因此,b在本书的例子中确实已经在范围中了。

以上描述和概念正确吗?

的确,这本书的结论是错误的。函数内的var b任何位置意味着b存在于函数内的任何位置。这就是"提升"。所有varfunction声明都被提升到顶部,无论它们在范围中的位置如何。还没有分配。

关于代码:

assert(typeof b === "number", "b is in scope");
var b = 1;

声明:

"b还不在范围内,直到它被宣布为"

是错误的。b"在作用域中"(因为它已声明,所以它是在执行任何代码之前创建的),但尚未分配值,因此typeof b返回undefined,测试失败。

以上描述和概念正确吗?

是的,或多或少。一个更简单的证明是:

function foo() {
  alert(b);
  var b = 5;
}
function bar() {
  alert(x);
  x = 5;
}
foo() // 'undefined' since b is "in scope" but hasn't been assigned a value yet
bar() // throws an error since x isn't "in scope" until the following line.