2016-12-21 59 views
8

最近我在Chrome控制台中遇到了这个奇怪的事情。在这里,我故意将一个未定义的事情分配给a,以便引发错误。Chrome控制台已经声明的变量抛出未定义的参考错误,让

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

然后,当我试图分配的东西合法的,发生这种情况:

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

,所以我不能用“让”,因为一个已经被声明。于是,我就重新分配别的东西来了“已经宣称为”

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

所以好像我不能重新分配别的东西的,但在同一时间,一个已被宣布所以我不能用再来一次。

我明白声明和分配变量的区别。然而在这里,似乎都不能再做。这是否与控制台中“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语句VS隐含的情况有些区别。

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

虽然在这种情况下可以重新分配示例。

let example 
throw new Error 
example = 5 
+0

@JaromandaX固定错别字对不起 – whales

+0

貌似控制台在chrome中是以严格模式开始的 - 类似的问题在firefox中,除了'a =“合法字符串”''每次都适用 –

+0

这似乎是一个烦恼铬控制台,当然 - 但是,这将不会有任何影响网页**在所有** –

回答

6

当您将暂时死区引入全局范围时会发生这种情况。您可能知道,let声明are hoisted but left uninitialised。由于控制流量,可能会发生变量永远不会被初始化:

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; 

与函数作用域相反,变量保持未初始化的确如此重要。全球范围永远持续,变量是永久死亡。它不是,也不会被初始化,词法变量不能重新声明(这有助于防止错误)。

was discussed on es-discuss,但认为无关紧要。如果顶级<script>执行会引发错误,那么您的问题比未初始化的变量更大。没有恢复的路径。如果你需要一个(例如试图用连续的脚本重新声明它),那么你必须使用var

,你必须在devtools控制台同样的问题是有点讨厌的,但可以解决的控制台作为一个特殊的范围。

+0

考虑到挂起,我写了这样的代码:“let x; throw new Error; x = 6”,在这种情况下,x实际上可以在稍后重新分配。 “手动”提升声明语句与隐式实现之间是否存在细微差别?我加入了更好的格式的后续问题 – whales

+0

是的,'let x;'是'let x = undefined;'的快捷方式,如果您手动将它放在顶部,您将在异常获得之前初始化变量抛出。 – Bergi

+0

Re“没有恢复的路径”,将来它可能能够<脚本onerror' – Pacerier

1

你应该知道关于在JS提升。基本上,像这样的 let a = werwr;

声明解释为 let a; a = werwr;

这为什么当你运行你的代码,第二行已声明。

UPDATE

因此,有在ES规格一注 https://tc39.github.io/ecma262/#prod-LetOrConst

让和const声明定义被限定在 运行的执行上下文的LexicalEnvironment变量。变量为 ,当它们包含词法环境实例化时创建,但可能不会以任何方式访问 ,直到变量的LexicalBinding为 评估为。 LexicalBinding在初始化程序 中定义的变量在 评估LexicalBinding时被分配其初始化程序的AssignmentExpression的值,而不是在创建该变量时。如果 let声明中的LexicalBinding没有初始化程序 ,那么在评估LexicalBinding 时,该变量将赋予未定义的值。

...

意味着,声明必须成功完成,然后才能访问变量(“但不得以任何方式,直到可变的LexicalBinding评估访问”要么获得价值,分配值,或做typeof,或事件delete);

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

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

请点击链接并阅读更多。如果你找到一种方法来恢复变化a,请告诉我。 谢谢,今天我发现了一些关于Javascript的新东西。

+0

如果是那样的话,我应该能够做到“一个=‘合法的串’,但它抛出a没有定义的错误,如果我像你一样单独编写语句,我可以重新分配a。但是在我的情况下,这不会发生 – whales

+0

你说得对,我现在最后的解释是Chrome开发者工具运行你的脚本通过eval()。我试图做一个例子,但是,用'let'在eval()内....好吧,祝你好运。 – vothaison

+1

感谢您的研究。Bergi的答案相当详尽你有兴趣 – whales