What causes the different behaviors between "var" and "let" when assign them a returned value of a function which throws an error

Please find the code in the image below. 1. Assign the returned value of a function, which throws an error actually, to the variable 'withLet' that declared by using keyword 'let'. 2. call 'withLet', an error occured: 'withLet is not defined'. 3. try to assert 'withLet' using 'let', an error shows that 'withLet' has already been declared.

But the paradox is not exist for 'var' (Please find in the following image).

I'm curious about what caused the different behaviors between these two situations. It's quite wired that 'not defined' an 'already been declared' describe a same variable.

let withLet = (function() {throw 'error!'})()
var withVar = (function() {throw 'error!'})()
//VM2470:1 Uncaught error!
//(anonymous) @ VM2470:1
//(anonymous) @ VM2470:1
withLet
//VM2484:1 Uncaught ReferenceError: withLet is not defined at 
//<anonymous>:1:1
//(anonymous) @ VM2484:1
withVar
//undefined
let withLet = 'sth'
//VM2520:1 Uncaught SyntaxError: Identifier 'withLet' has already been 
//declared
//at <anonymous>:1:1
//(anonymous) @ VM2520:1
withVar = 'sth'
//"sth"

Screenshot:


Solution 1:

Declarations of var variables get hoisted - the variable name initialization gets hoisted to the top of the containing function (or, if no function, to the top of the outer block). So

var withVar = (function() {throw 'error!'})()

is parsed by the interpreter as

var withVar;
withVar = (function() {throw 'error!'})()

The same is not true for let - let variables become initialized once the let __ line runs. When there's assignment, the right-hand side is parsed first; if the right-hand side throws an error, it never gets to the left-hand side, and the variable declared with let never gets properly initialized; it'll stay in the demilitarized zone / temporal dead zone forever, so trying to reassign it throws an error.

It's kind of weird because the code is being run in the console - ordinarily, JS runs inside a <script> tag, and if such an error occurs, usually no more code will run, and the fact that a variable declared with let is no longer reassignable is the least of your worries.


The above was an issue in earlier Chrome versions. But in Chrome 80+, re-declarations of let are now permitted, so the error

Uncaught SyntaxError: Identifier 'withLet' has already been declared

should no longer occur, regardless of whether the previous initialization of the variable succeeded or not:

enter image description here