Recently I ran into this weird thing in chrome console. Here I am intentionally assigning an undefined thing to a in order to throw an error.
let a = werwr // Uncaught ReferenceError: werwr is not defined
Then when I tried to assign something legit to a, this happened:
let a = "legit string" // Uncaught SyntaxError: Identifier 'a' has already been declared
so I can't use "let" because a has already been declared. So I tried to reassign something else to the "already declared a"
a = "legit string" // Uncaught ReferenceError: a is not defined
So it seems like I can't reassign something else to a but at the same time, a has been declared so I can't use let again.
I understand the difference between declaring and assigning a variable. However here it seems that neither could be done again. Does this has something to do with the scope of "let" in console? Because the same thing totally works for "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
Follow-up
There seem to be some difference between "manually" hoisting the let statement vs the implicit case.
throw new Error
let example = 5
// same errors as before
while in this case example can be reassigned again.
let example
throw new Error
example = 5
This happens when you introduce the temporal dead zone to the global scope. As you might know,
let
declarations are hoisted but left uninitialised. Due to control flow, it can happen that a variable is never initialised:This is fine in a function scope. Maybe something went wrong, maybe the variable wasn't needed at all - in the next call, a new scope with a new variable will be created.
A similar thing can happen in the global scope, when you throw an exception before the variable is initialised (only exceptions work here as a control flow construct, nothing else achieves the same effect).
In contrast to the function scope, it does matter here that the variable stays uninitialised. The global scope lasts forever, and the variable is eternally dead. It was not and will never be initialised, and lexical variables cannot be re-declared (which helps preventing mistakes).
This was discussed on es-discuss, but deemed irrelevant. If top-level
<script>
execution throws an error, you have bigger problems than uninitialised variables. There is no path to recover. If you need one (e.g. by trying to re-declare it in successive scripts), you have to usevar
anyway.That you have the same problem in the devtools console is a bit of a nuisance, but could be solved for the console as a special scope.