【问题标题】:When would one be unable to determine if a let or const was initialised?什么时候无法确定 let 或 const 是否被初始化?
【发布时间】:2017-09-06 04:31:05
【问题描述】:

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

Crunchy 性能细节:在大多数情况下,您可以判断 声明是否运行仅通过查看代码,所以 JavaScript 引擎实际上不需要执行额外的检查 每次访问变量以确保它已经 初始化。然而,在闭包内部,有时并不清楚。在 在这些情况下,JavaScript 引擎会进行运行时检查。这意味着 let 可能比 var 慢一点。

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

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

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

即使在函数结束时返回闭包,也可以保证 return 语句永远不会执行,即使 x 已分配给 q 的成员(并且因此可能会逃到野外)x 永远不会被初始化,因此crash 将永远崩溃。

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

【问题讨论】:

  • crash() 甚至不会被执行,当您尝试将x 分配给q.fn 时,它已经崩溃了。
  • 这应该是 q.fn = crash。感谢您了解这一点。
  • 顺便说一句,你能把这篇文章和那个引用链接起来吗?
  • 契约完成了。

标签: javascript ecmascript-6 closures let scoping


【解决方案1】:

只需将其置于仅有时会满足的条件中:

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

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

【讨论】:

  • @BekimBacaj 问题是“这是一个例子,很清楚x在访问时是否被初始化;什么情况下不清楚? ",我已经展示了一个例子,它不是那么容易看到,而且不能在每种情况下都确定。
【解决方案2】:

没有慢或快句柄之类的东西,即:命名值,无论是 var、const 还是 let。也没有“无法确定”它们是否已初始化之类的东西。 此外,let/s 不会被初始化——它们只是被分配。并且由于它们的行为类似于“未声明的变量”,因此它们将在运行时并准确地在它们的点声明时被赋值。

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

【讨论】:

  • 您可能想查看this,了解let/const 的“声明”和“初始化”的含义。
  • 嗯,它们的行为与 imo 完全不同。是的,虽然解释器总是可以确定(测试)变量是否已经初始化,但我们正在讨论确定是否需要进行此类测试的编译器优化。哪个是不可判定的。
  • 在条件\块\本地范围内有一个错误\错误的实现和错误的行为,在失败的环顾后阻碍了查找原则,如:function lookupDisabled(){ const myval = 1; console.log( myval ); if(myval === 1) { /*console.log( myval ); ReferenceError*/ const myval = 2; console.log( myval ); if( myval === 2 ){ /*console.log( myval ); ReferenceError*/ const myval = 3; console.log( myval );} console.log( myval ); } return myval; } 注释日志的位置myval 应该能够在外层范围内查找日志 1。
  • 不,这既不是错误也不是错误。请查看my answer 了解其工作原理。还有it's very much on purpose.
  • 任何违反直觉的、意外的、因此是错误的行为;特别是那些违背给定语言的基本编程原则的定义,通常被认为是一个错误。这是无缘无故地打破了查找原则。这是解析时过早且错误的先行包含优化(可能会节省几个 cpu 周期),但仍然是一个错误。仅仅因为给定值的标识符正在等待声明,不应该成为使其无法访问的理由,尤其是当创建当前上下文的条件说 !0 时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2021-10-19
  • 1970-01-01
  • 2012-06-13
  • 2016-12-10
相关资源
最近更新 更多