问题 Chrome控制台已声明变量为let发出未定义的引用错误


最近我在chrome控制台遇到了这个奇怪的事情。在这里,我故意为a分配一个未定义的东西,以便抛出错误。

let a = werwr // Uncaught ReferenceError: werwr is not defined

然后,当我尝试为a分配合法的东西时,发生了这种情况:

let a = "legit string"   // Uncaught SyntaxError: Identifier 'a' has already been declared

所以我不能使用“let”,因为已经声明了。所以我试图将其他东西重新分配给“已经宣布为”

a = "legit string"   //  Uncaught ReferenceError: a is not defined

因此,我似乎无法将其他内容重新分配给a,但与此同时,a已被声明,因此我不能再使用let。

我理解声明和赋值变量之间的区别。然而,似乎这两者都不能再做了。这是否与控制台中“let”的范围有关?因为同样的事情完全适用于“var”

var a = werwr 
// Uncaught ReferenceError: werwr is not defined

a = ”legit string“  
// ”legit string“

var a = "legit string" 
// Uncaught SyntaxError: Identifier 'a' has already been declared

跟进

“手动”提升let语句与隐式大小写之间似乎存在一些差异。

throw new Error
let example = 5
// same errors as before

而在这种情况下,可以再次重新分配示例。

let example
throw new Error
example = 5

6234
2017-12-21 04:26


起源

@JaromandaX修复了拼写错误 - whales
看起来Chrome中的控制台是严格模式的开始 - 在Firefox中类似的问题,除了 a = "legit string" 每次都有效 - Jaromanda X
这似乎是Chrome控制台中的一个烦恼,当然 - 但这不会对网页产生任何影响 一点都不 - Jaromanda X
@JaromandaX感谢好奇。这有点令人讨厌bc如果发生这种情况我每次都要刷新。由于这些错误,我无法再次重新定义 - whales
github.com/eslint/eslint/issues/4278 - Pacerier


答案:


将时间死区引入全局范围时会发生这种情况。你可能知道, let 声明 被悬挂但尚未初始化。由于控制流,可能会发生变量从未初始化:

function …() {
    if (false)
        example; // would throw a ReferenceError if it was evaluated
    … // do something
    if (true)
        return; // stop!
    let example = 5; // never executed
}

这在功能范围内很好。也许出了点问题,也许根本不需要变量 - 在下一次调用中,将创建一个带有新变量的新范围。

类似的事情可能发生在全局范围内,当你在变量初始化之前抛出一个异常时(只有异常在这里作为控制流构造工作,没有其他任何东西达到相同的效果)。

throw new Error;
let example = 5;

与函数范围相反,这里变量保持未初始化非常重要。全局范围永远持续,变量是 永远死了。它不是也不会被初始化,并且词法变量不能被重新声明(这有助于防止错误)。

这个 在讨论中进行了讨论,但被视为无关紧要。如果顶级 <script> 执行会抛出错误,你比未初始化的变量有更大的问题。没有恢复的途径。如果你需要一个(例如通过尝试在连续的脚本中重新声明它),你必须使用 var 无论如何。

你在devtools控制台中遇到同样的问题有点令人讨厌,但可以作为一个特殊的范围解决控制台问题。


9
2017-12-21 06:03



考虑到let被挂起,我写了这样的代码:“let x; throw new Error; x = 6”在这种情况下,x实际上可以在以后重新分配。 “手动”提升声明语句与隐式实现之间是否有任何细微差别?我用更好的格式添加了问题的后续跟进 - whales
是, let x; 是一个快捷方式 let x = undefined;,如果你手动将它放在顶部,你将在抛出异常之前初始化变量。 - Bergi
重新“没有恢复的道路”,将来也许能够 <script onerror - Pacerier
@Pacerier你可以 处理 错误(今天已经有了 window.onerror)并记录它,但你不能 恢复 它。在抛出异常之前撤消脚本所做的事情是不可能的,并且不可能取消声明变量。 - Bergi


你应该知道在JS中提升。基本上,这样的声明 let a = werwr;

被解释为 let a; a = werwr;

这就是为什么在运行第二行代码时已经声明了。

UPDATE

因此,ES规范中有一个注释 https://tc39.github.io/ecma262/#prod-LetOrConst

let和const声明定义作用域的变量   运行执行上下文的LexicalEnvironment。变量是   在实例化包含词汇环境时创建 但   在变量的LexicalBinding之前,可能无法以任何方式访问它   评估。由带有初始化程序的LexicalBinding定义的变量   被赋值为Initializer的AssignmentExpression的值   评估LexicalBinding,而不是在创建变量时。如果   let声明中的LexicalBinding没有Initializer   在LexicalBinding中为变量赋值undefined   被评估。

...

“但在评估变量的LexicalBinding之前,可能无法以任何方式访问” 意味着,必须先成功完成声明才能访问变量(获取值,赋值或执行操作) typeof或事件 delete);

在您的情况下,变量的LexicalBinding由异常中断。

let a = werwr // Uncaught ReferenceError: werwr is not defined

请点击链接,了解更多相关信息。如果你找到了恢复变种的方法 a, 请告诉我。 谢谢,今天我发现了一些关于Javascript的新内容。


1
2017-12-21 04:30



如果是这种情况,我应该可以做“a =”合法的字符串“,但它抛出了a未定义的错误。如果我像你一样单独编写语句,我可以重新分配a。但是在我的情况下,它没有发生 - whales
你是对的,我现在的最后解释是Chrome开发者工具通过eval()运行你的脚本。我想试试这个例子。但是,随着 let 在eval()里面......好吧。祝你好运。 - vothaison
谢谢你做了研究。如果你有兴趣,Bergi的回答非常彻底 - whales
非常感谢 ... - vothaison