Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript Using let with for Loops

Still difficult to understand this loop!

Hi everyone,

I still have difficult to understand why, in the initial loop, we always see "Button 10 pressed" using the var keyword. Can somebody explain me better why is happening that?? What's the difference between using var and let?? Why using var the alert always show "Button 10 pressed"?? Thanks everybody!

4 Answers

It has to do with the way var and let variables are registered. When you declare a var variable, it is visible within the entire function or the global space while a let variable may neither be accessed outside of its scope nor before its declaration.

A for-loop is a shorthand for writing:

var i = 0;
for (i < buttons.length; ++i) {

}

It is not because every button has the exact same function attached to it that it prints 10, rather every button has its own version of the defined function, but the variable i declared in everyone of those function refers to the global variable i, which is set to 10 after the final iteration.

If we were to use the let variable instead, it would declare the variable within the event handler. Consequently, each button click will refer to its local version of the variable i which is set to whatever it was set to during the loop.

Corey Hayden
Corey Hayden
11,717 Points

Thank You!! now I get it!! of all the attempts to explain this problem, I find this to be the best!!

Am I also correct in thinking that expressions in event listener functions are evaluated only when they are called by the event they are assigned to? (as opposed to when they are assigned to the event?) As such, by the time an event is triggered, if its method references a global variable, that variable might well have changed since the moment it was attached, as in this case.

Corey Hayden, you are very much correct. JavaScript makes two passes of our code, on the first one it checks for function declaration, and on the second and final pass it runs the rest of your code. Everything on the second pass is undefined until it has been evaluated. In this case, since our event handler is an anonymous function it is parsed under the second pass, and thus is evaluated at runtime, as you suggested.

Click the button immediately, wait for a second, click it again.

const buttons = document.getElementsByTagName("button");

for(var i = 0; i < buttons.length; i++) {
     const button = buttons[i];
     button.addEventListener("click", function() {
        alert("Button " + i + " Pressed");
    });
}

setTimeout(() => {
      i = 12;
}, 1000);

Indeed, the variable may as well have been changed since the moment it was attached.

for(var i = 0; i < buttons.length; i++) { const button = buttons[i]; button.addEventListener("click", function() { alert("Button " + i + " Pressed"); }); }

How come the constant variable button's value change every time it go through loop? confused

Franklyn Roth
Franklyn Roth
16,770 Points

It was much easier for me to understand the concept in the example code at the following link. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}
Stephan Edmonson
Stephan Edmonson
1,368 Points

Really helpful example. Thanks for sharing!

It has to do with scopeing. Re watch the video he explains it.

Also google or YouTube: JavaScript execution context.

This may give you a better understanding of what scoping is.

How come the constant variable button's value change every time it go through loop? confused

Ryan Shrestha, const and let are only visible after they've been declared and within their block scope. This means constant variables are visible within nested blocks.

if (2 < 3) {
    const message = "first block-scope";

    if (3 < 5) {

        // nested block-scope
        console.log(message);
    }

}

But constants within nested blocks are not visible to the outer (or parent) block.

if (2 < 3) {
    // parent block.

    if (3 < 5) {
        const message = "nested block"
    }

    console.log(message); // uncaught ReferenceError: message is not defined
}

Here comes the interesting but somewhat confusing part. Since nested constant variables are not visible outside of their block, you can declare a new constant with the same name as the constant in the outer block.

if (2 < 3) {
    // parent block
    const message = "first block-scope";

    if (3 < 5) {

        const message = "second block-scope";
        console.log(message);

    }

    console.log(message);
}

Output:

second block-scope
first block-scope

This means the constant variable within the nested block, effectively overwrites the outer constant, making it no longer visible within the nested block. This is what is happening to the button constant that we declare in every iteration of the for-loop.

Think of it this way, since the outer constant do not know that I've overwritten it (the new constant is out of its scope), it doesn't throw any error.

if (2 < 3) {
    // parent block
    const message = "first block-scope";

    if (3 < 5) {


        console.log(message);

    }

    console.log(message);
}

But you can still have access to the outer constant variable if you do not redeclare a new constant variable with the same name.