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

JavascriptVariable Declaration

Javascript Problem Overview


I can't understand why variables act so strange when declared inside a function.

  1. In the first function I declare with let the variables b and c with the value 10:

     b = c = 10;
    

    In the second function I show:

     b + ", " + c
    

    And this shows:

     10, 10
    
  2. Also in first function I declare a with value 10:

     let a = b = c = 10;
    

    But in the second function it shows an error:

    > Can't find variable: a

  3. Now in the first function I declare d with value 20:

     var d = 20;
    

    But in the second function it shows the same error as before, but with the variable d:

    > Can't find variable: d

Example:

function first() {
  let a = b = c = 10;
  var d = 20;
  second();
}

function second() {
  console.log(b + ", " + c); //shows "10, 10"

  try{ console.log(a); }  // Rreference error
  catch(e){ console.error(e.message) }

  try{ console.log(d); } // Reference error
  catch(e){ console.error(e.message) }
}
first()

Javascript Solutions


Solution 1 - Javascript

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".

Solution 2 - Javascript

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();

Solution 3 - Javascript

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
}

Solution 4 - Javascript

Variables using the let keyword should only be available within the scope of the block and not available in an outside function...

Each variable that you are declaring in that manner is not using let or var. You are missing a comma in the variables declaration.

It is not recommended to declare a variable without the var keyword. It can accidentally overwrite an existing global variable. The scope of the variables declared without the var keyword become global irrespective of where it is declared. Global variables can be accessed from anywhere in the web page.

function first() {
   let a = 10;
   let b = 10;
   let c = 10;
   var d = 20;
   second();
}

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

first();

Solution 5 - Javascript

It's because of when you don't use let or var then variable is getting declare on the fly, better you declare like following.

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

Solution 6 - Javascript

The strange issue is caused by scoping rules in JavaScript

function first() {
   let a = b = c = 10; // a is in local scope, b and c are in global scope
   var d = 20; // d is in local scope
   second(); // will have access to b and c from the global scope
}

Assuming that you want to declare 3 local variables initialised to the same value (100). Your first() will look like below. In this case, second() will not have access to any of the variables because they are local to first()

function first() {
   let a = 100; // a is in local scope init to 100
   let b = a; // b is in local scope init to a
   let c = b // c is in local scope init to b

   var d = 20; // d is in local scope
   second(); // will not have access a, b, c, or d
}

However, if you want global variables then your first() will look like below. In this case, second will have access to all the variables because they are in global scope

function first() {
   a = 100; // a is in global scope
   b = a; // b is in global scope
   c = b // c is in global scope

   d = 20; // d is in global scope
   second(); // will have access to a, b, c, and d from the global scope
}

Local variables (aka. accessible in the code block where they are declared).
A Code block is any {} with line(s) of code between.

  • function() {var, let, const in here is accessible to entire function},
  • for() {var in here is accessible to outer scope, let, const accessible only in here},
  • etc.

Global variables (aka accessible in the global scope).
These variables are attached to the global object. The global object is environment dependent. It is the window object in browsers.

Special note: You can declare variables in JavaScript without using the var, let, const keywords. A variable declared this way is attached to the global object, therefore accessible in the global scope.
a = 100 // is valid and is in global scope

Some articles for further reading: https://www.sitepoint.com/demystifying-javascript-variable-scope-hoisting/ https://scotch.io/tutorials/understanding-scope-in-javascript https://www.digitalocean.com/community/tutorials/understanding-variables-scope-hoisting-in-javascript

Solution 7 - Javascript

Main difference is scoping rules. Variables declared by var keyword are scoped to the immediate function body (hence the function scope) while let variables are scoped to the immediate enclosing block denoted by { } (hence the block scope). And when you say

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

c and b have the life span as fun have but a only have block span and if you try to access a by referencing it always show error but c and b are globally so they don't.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 break-point). 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 break-point in the second function), but the other two (or however many you add) are still available.

Solution 8 - Javascript

Here are the 3 interesting aspects of variable declarations in JavaScript:

  1. var restricts the scope of variable to the block in which it is defined. ('var' is for local scope.)

  2. let allows temporary overriding of an external variable's value inside a block.

  3. Simply declaring a variable without var or let will make the variable global, regardless of where it is declared.

Here is a demo of let, which is the latest addition to the language:

// File name:  let_demo.js

function first() {
   a = b = 10
   console.log("First function:    a = " + a)
   console.log("First function:    a + b = " + (a + b))
}

function second() {
    let a = 5
    console.log("Second function:    a = " + a)
    console.log("Second function:    a + b = " + (a + b))
}

first()   

second()

console.log("Global:    a = " + a)
console.log("Global:    a + b = " + (a + b))

Output:

> $ node let_demo.js >
> First function: a = 10 > First function: a + b = 20 >
> Second function: a = 5 > Second function: a + b = 15 >
> Global: a = 10 > Global: a + b = 20

Explanation:

The variables a and b were delcared inside 'first()', without var or let keywords.

Therefore, a and b are global, and hence, are accessible throughout the program.

In function named 'second', the statement 'let a = 5' temporarily sets the value of 'a' to '5', within the scope of the function only.

Outside the scope of 'second()', I.E., in the global scope, the value of 'a' will be as defined earlier.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionbleat interteimentView Question on Stackoverflow
Solution 1 - JavascriptTim ConsolazioView Answer on Stackoverflow
Solution 2 - JavascriptCidView Answer on Stackoverflow
Solution 3 - JavascriptfatimasajjadView Answer on Stackoverflow
Solution 4 - JavascriptJonoJamesView Answer on Stackoverflow
Solution 5 - JavascriptMohit RathodView Answer on Stackoverflow
Solution 6 - JavascriptFunwieView Answer on Stackoverflow
Solution 7 - JavascriptMuhammad FahadView Answer on Stackoverflow
Solution 8 - JavascriptGopinathView Answer on Stackoverflow