Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird (let) variable assignment behavior in node repl - can't assign values

I'm using Node v12.14.1 on Windows 10 in cmd.
When assigning the value of an undefined function to a variable:

let a = f();

I get:

Thrown:
ReferenceError: f is not defined

Which is fine. But when I try:

a = 2;

I now get:

Thrown:
ReferenceError: a is not defined

And when I try:

let a = 2;

I get:

Thrown:
SyntaxError: Identifier 'a' has already been declared

So, a variable declared using let, when assigned the value of an undefined function, has its identifier already declared, and is not defined, at the same time.
Is this intended? Am I missing something here? Is this a bug?
The same does not happen when using var in the undefined function assignment, or when not using anything (global variable).

like image 620
Vedaant Arya Avatar asked May 12 '20 16:05

Vedaant Arya


1 Answers

REPLs are funny, but no, this behavior isn't a bug, it is indeed per spec. It's something you couldn't see in a non-REPL environment, though.

A let statement creates a binding¹ upon entry to the scope where let appears, but doesn't initialize it (unlike var, which initializes it with undefined). (In the case of the REPL "entering the scope" is basically just before it executes the code you've given it.) The initialization happens when the initialization part of the let statement happens, later when you you reach that statement in the step-by-step execution.² In your code, though, you never reach that part of the statement, because when the initializer was evaluated, it threw an error.

At that point, there's nothing you can do with a, because it exists but isn't initialized, and the only thing that could have initialized it (the result of the initializer in the original let a = f();) failed and can't be run again.

The reason you can't see that in non-REPL code is that the error would take you out of the scope where a has been created but not initialized. consider:

try {
    let a = f(); // ReferenceError
    // Execution in this block never continues
} catch {
    // Execution arrives here...but `a` is not in scope
}

¹ binding - an entry for the variable in the execution context's environment record

² If the let statement doesn't have an initializer, undefined is used at this point.

like image 193
T.J. Crowder Avatar answered Nov 08 '22 07:11

T.J. Crowder