Why do some variables declared using let inside a function become available in another function, while others result in a reference error?

It's because you're actually saying:

c = 10;
b = c;
let a = b;

And not what you think you are saying, which is:

let a = 10;
let b = 10;
let c = 10;

You'll notice that no matter how many variables you add to your chain, it will only be the first (a) that causes the error.

This is because "let" scopes your variable to the block (or, "locally", more or less meaning "in the brackets") in which you declare it.

If you declare a variable without "let", it scopes the variable globally.

So, in the function where you set your variables, everything gets the value 10 (you can see this in the debugger if you put a breakpoint). If you put a console log for a,b,c in that first function, all is well.

But as soon as you leave that function, the first one (a)--and again, keep in mind, technically in the order of assignment, it is the last one-- "disappears" (again, you can see this in the debugger if you set a breakpoint in the second function), but the other two (or however many you add) are still available.

This is because, "let" ONLY APPLIES TO (so only locally scopes) THE FIRST VARIABLE--again, which is technically the last to be declared and assigned a value--in the chain. The rest technically do not have "let" in front of them. So those are technically declared globally (that is, on the global object), which is why they appear in your second function.

Try it: remove the "let" keyword. All your vars will now be available.

"var" has a similar local-scope effect, but differs in how the variable is "hoisted", which is something you should definitely understand, but which is not directly involved with your question.

(BTW, this question would stump enough pro JS devs to make it a good one).

Strongly suggest you spend time with the differences in how variables can be declared in JS: without a keyword, with "let", and with "var".


In the function first(), variables band c are created on the fly, without using var or let.

let a = b = c = 10; // b and c are created on the fly

Is different than

let a = 10, b = 10, c = 10; // b and c are created using let (note the ,)

They become implicit global. That's why they are available in second()

From documentation

Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed.

To avoid this, you can use "use strict" that will provide errors when one use an undeclared variable

"use strict"; // <-------------- check this

function first() {
   /*
    * With "use strict" c is not defined.
    * (Neither is b, but since the line will be executed from right to left,
    * the variable c will cause the error and the script will stop)
    * Without, b and c become globals, and then are accessible in other functions
    */
   let a = b = c = 10;
   var d = 20;
   second();
}

function second() {
   console.log(b + ", " + c); //reference error
   console.log(a); //reference error
   console.log(d); //reference error
}

first();


Before calling things strange, let’s know some basics first:

var and let are both used for variable declaration in JavaScript. For example,

var one = 1;
let two = 2;

Variables can also be declared without using var or let. For example,

three = 3;

Now the difference between the above approaches is that:

var is function scoped

and

let is block scoped.

while the scope of the variables declared without var/let keyword become global irrespective of where it is declared.

Global variables can be accessed from anywhere in the web page (not recommended because globals can be accidentally modified).

Now according to these concepts let's have a look at the code in question:

 function first() {
   let a = b = c = 10;
   /* The above line means:
    let a=10; // Block scope
    b=10; // Global scope
    c=10; // Global scope
    */

   var d = 20; // Function scope
   second();
}

function second() {
   alert(b + ", " + c); // Shows "10, 10" //accessible because of global scope
   alert(a); // Error not accessible because block scope has ended
   alert(d); // Error not accessible because function scope has ended
}