将let变量移出暂时性死区

8

看这段代码:

<script>
let {foo} = null; // TypeError
</script>
<script>
// Here I want to assign some some value to foo
</script>

第一个脚本尝试通过解构赋值来声明foo,但是null无法进行解构,因此该赋值语句会抛出TypeError异常。
问题在于foo变量被声明但未初始化,因此如果在第二个脚本中尝试引用foo,它会抛出异常:
foo = 123; // ReferenceError: can't access lexical declaration `foo' before initialization

let变量不允许被重新声明:

let foo = 123; // SyntaxError: redeclaration of let foo

有没有办法将它从TDZ中取出,以便我可以分配值并读取它们?

顺便提一下,我想使用 foo,而不是诸如 window.foo 这样的解决方法。 - Oriol
我猜第一个脚本中有一些有趣的东西,使得确保初始化的有效性变得困难。 - Pointy
@Oriol:window.foo 无论如何都不会起作用 :-) - Bergi
1
你在什么环境中执行这个程序(浏览器,版本号)?它的ES6支持程度如何,可能只是一个bug吗? - Bergi
2
我刚刚查看了规范,这种行为似乎是正确的。我还发现了第三个合理的尝试,但它也不起作用:delete foo; - Bergi
显示剩余5条评论
1个回答

2
这是不可能的。暂时性死区和对未初始化的let变量的限制访问被认为是无法避免的。这很令人困惑和有问题,但这是有意的并且是预期的。
详见规范
引用:

注意,let和const声明定义了作用域限定在运行执行上下文的词法环境中的变量。当它们所在的词法环境实例化时创建这些变量,但在变量的词法绑定求值之前无法以任何方式访问这些变量。由LexicalBinding定义的变量如果带有Initializer,则在评估LexicalBinding时将其分配为Initializer的AssignmentExpression的值,而不是在创建变量时。如果在let声明中的LexicalBinding没有Initializer,则在评估LexicalBinding时将变量分配为undefined的值。

因此,如果变量在声明时未初始化(显然在初始化之前抛出异常会导致未初始化),则无论如何都无法访问该变量。
但事实上,您的问题比抛出赋值更复杂。这是架构问题——您依赖于可变全局变量。这是一个大问题,您应该重构代码以使用明确的依赖项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接