2

I`m confused about Set type in JS. If you create variable with not properly initialized Set, you cannot use it anymore (as Set nor primitive). Try in console:

let someSet = new Set(4);
/* Uncaught TypeError: number 4 is not iterable (cannot read property Symbol(Symbol.iterator))
    at new Set (<anonymous>)*/

someSet
// Uncaught ReferenceError: someSet is not defined 

let someSet = new Set([4])
// Uncaught SyntaxError: Identifier 'someSet' has already been declared
someSet
// Uncaught ReferenceError: someSet is not defined

let someSet = 'ho-ho-ho'
// Uncaught SyntaxError: Identifier 'someSet' has already been declared

someSet = 'ho-ho-ho'
// Uncaught ReferenceError: someSet is not defined

Can you explain me why? See screen:

enter image description here

adiga
  • 34,372
  • 9
  • 61
  • 83
Musical Echo
  • 143
  • 2
  • 7

1 Answers1

8

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:

  1. Declare (but not initialize) the variable (binding) someSet
  2. Evaluate the initializer new Set(4)
  3. 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).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • [Link to the temporal dead zone documentation of let](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone) – Carsten May 21 '19 at 13:19
  • yeap. works with `var` at first place. so that means, that the problem is with `let`, but not `Set` type – Musical Echo May 21 '19 at 13:22
  • @MusicalEcho - Yes, this has nothing to do with `Set`. It's not a problem with `let`; you could argue it's a problem with Chrome's console. – T.J. Crowder May 21 '19 at 13:26
  • @MusicalEcho - No worries. I couldn't help myself and updated it further. :-) – T.J. Crowder May 21 '19 at 13:37