let Variable Scope

4k views Asked by At

The following code will output "1." However, shouldn't the keyword "let" not make x a global variable, thus making it invisible to das()? let is supposed to limit the scope of variables to only the block where they're declared, yet here, I'm seeing an inner function have access to a "let" variable, even though x was declared outside its scope. How is that possible?

function letTest() {
 function das () {
  console.log(x);
// How does this function have access to a let variable declared outside its scope?
 }

 let x = 1;
 das();
}
letTest();

7

There are 7 answers

4
Pointy On BEST ANSWER

Here's a way of thinking about how let works:

  1. Start from the let.
  2. At the same nesting level, working back/up through the source code, find the first {.
  3. Now from the let find the corresponding }.

That gives you the scope wherein the variable will be visible. If a function definition appears in that scope, fine; the variable is visible to code in that function.

Now, what's a little bit weird is that in your example the variable looks like it's used in the scope before it's declared. That's where the fact that the reference appears before the declaration becomes a little more interesting.

Normally, if code in a scope refers to a let-declared variable before the let actually happens, that's an error. However, that's a runtime thing, not a syntax thing. In your case, at runtime the let will have "happened" by the time the nested function is called.

0
Quentin On

let limits the scope of the variable to the current block (in this case that is the same as the letTest function).

The das function is declared inside that scope, so it has access to anything in that scope (including x).

0
ekeith On

The thing is that you are not mutating the value of x, in your case you are just logging it to the console and they are all nested under one scope which does not limit the inner function, so your result is expected.

Now if you did something like this

function letTest() {
    function das () {
        console.log(x);
// How does this function have access to a let variable declared outside its scope?
    }
    let x = 1;
    function change(){
       x = x + 1;
    }

    change();
}
letTest();

Now you are trying to change the value of x and the compiler would complain.

0
nickmcblain On

As described here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let it provides access within the block scope. As your das() execution and x declaration are in the same block scope it will have access.

A good example is in the switch case below, using var x = 'x' in case 1 will cause it to attach to the function scope and accessible in the console.log() but when trying to reference the bar variable for logging it throws a reference exception. But still works in the default case.

const example = (foo) => {
    switch(foo) {
        case 0:
            break;
        case 1:
            let bar = 'bar';
            var x = 'x';
            break;
        default:
            console.log(bar);
            break;
    }

    console.log(x);
    console.log(bar);
}

example(1);
0
Oriol On

The function is declared in the same block as x, so the code inside the function has access to x.

If you don't want that, you can always add a new block:

function letTest() {
  function das () {
    console.log(x); // ReferenceError
  }
  { // New block
    let x = 1;
    das();
  }
}
letTest();

0
Bekim Bacaj On

@GTS Joe,

the let x is local to the letTest() context, therefore das() is simply accessing its xvariable. Nothing strange is going on there. So, 'no' - it's not becoming global.

No matter how deep the context of the variable call has been nested, there's always a look-up JS principle, that will follow on a failed look around and will continue to look up for this variable name all the way through the global scope, and only then - when nothing's found - it will cause a reference error.

And that - only because there's no look below JS principle - the so called closures are possible.

0
Agent86 On

It is not outside the scope. x and das() are defined in the same block scope. Anything else within that block has access to x. That includes any nested functions, for loops, while loops and if conditionals. That includes elseif and else that are inside the if conditional.