什么时候无法确定是否初始化了 let 或 const?

When would one be unable to determine if a let or const was initialised?

Jason Orendorff 在 letconst 上的 article 中声明如下:

Crunchy performance details: In most cases, you can tell whether the declaration has run or not just by looking at the code, so the JavaScript engine does not actually need to perform an extra check every time the variable is accessed to make sure it’s been initialized. However, inside a closure, it sometimes isn’t clear. In those cases the JavaScript engine will do a run-time check. That means let can be a touch slower than var.

我决定尝试找到一个例子,证明这是正确的,但被难住了。

例如,让我们看看下面的酷刑场景:

function doSomethingDumb(q) {
    function crash() { ++x; }
    q.fn = crash;
    crash();
    let x;
    return crash;
}

即使在函数末尾 returned 闭包,也保证 return 语句将 永远不会执行 ,即使x 被分配给 q 的成员(因此可能会逃逸)x 永远不会被初始化,因此 crash 总是会崩溃。

什么情况下无法判断变量是否已经初始化?

只是把它放到一个有时才满足的条件中:

function example() {
    if (Math.random() < 0.33) tryIt();
    const x = 5;
    if (Math.random() < 0.5) tryIt();
    function tryIt() {
        console.log(x);
    }
}

在这个例子中,我选择了随机数,但它也可以取决于函数的输入参数。通常,访问变量的语句是否会在初始化之前执行是静态不可判定的——即halting problem。您可以编写一个复杂的分析器来确定许多情况下的这一点,但分析器的复杂性和开销之间总是存在权衡。

没有慢句柄或快句柄之分,即:命名值,无论是 var、const 还是 let。如果它们也被初始化,则没有 "unable to determine" 这样的东西。 此外 let/s 不会被初始化——它们只是被分配。并且由于它们的行为类似于 'undeclared variables' ,因此它们将在运行时并在它们的点声明时被赋予它们的值。

因此,如果停止错误发生在 let 声明之上的一行。它将保持完全未申报状态。看代码就知道了