This seems to be related to some "magic" in how REPL input is handled. It's not really a property of how JavaScript normally works.
If you try this in a node.js file, in a <script>
, or even in an (0, eval)('...')
, you'll get "Cannot access 'a' before initialization" as expected. Note that even in the DevTools console this won't happen if you are in a paused debugger state.
In a non-paused state (only there), the DevTools allow you to declare variables as if you were continuously writing a script, and the declarations will persist across commands. There is clearly "magic" outside of regular JavaScript involved, because even eval
would create another temporary scope. That "magic" is handled by V8 itself. It is therefore pretty likely that whatever trickery is used here has the side effect of this slightly unexpected error. (I initially thought the side effect is that the variable declaration isn't hoisted, but if you do a = 0; const a = 1
then you get "Assignment to constant variable", so that doesn't seem to be the case.)
I tried to trace this to the source, but I got lost in the depths of V8. Nonetheless, I discovered (by opening another DevTools to debug the DevTools themselves!) that this only happens if the replMode
argument (that gets passed to the V8 backend's evaluate
method) is true. This can be verified by setting a breakpoint here and changing the value of options.replMode
.
replMode
is documented as follows:
Setting this flag to true enables let
re-declaration and top-level await
.
Note that let
variables can only be re-declared if they originate from replMode
themselves.