This is pretty much something that can only happen on the console, since in real code if the new Set
part of let someSet = new Set(4);
failed, the error would take you out of the scope where let someSet
was and so this question wouldn't come up.
Interactive consoles like the ones in browsers have to play some games with scope and such. You've ended up with a variable that's declared but not initialized (made ready for use); it's forever in the Temporal Dead Zone (TDZ), because the spec's InitializeBinding operation has never been performed on it. (Variables are "bindings" in an environment object [there are other kinds of bindings as well].) Unlike the variable bindings created by var
, the ones created by let
can be uninitialized. Here's an example:
{
// `x` is *declared* upon entry to this scope, but not *initialized* yet
x = 5; // Fails because the `x` binding isn't initialized yet
let x;
}
Again, your exact example is only possible in a console like Chrome's console. If new Set(4)
didn't throw an error, the line let someSet = new Set(4);
would do these things, in this order:
- Declare (but not initialize) the variable (binding)
someSet
- Evaluate the initializer
new Set(4)
- Use the resulting value from #2 to initialize the variable
The problem is that since new Set(4)
threw an error, step 3 never occurred. In a normal environment, that error would take you out of the scope where someSet
was declared, but not in Chrome's console. As a result, you can't use someSet
at all, because you can't declare it again (it's already been declared), and you can't read its value (it doesn't have one, it's uninitialized), and you can't write a value to it (because the operation that does that, SetMutableBinding, checks whether the variable has been initialized and fails if it hasn't — because that's how the TDZ works).