0

I am going through a video on the new ECMA 6 JS. I have read the MDN and other web pages on let. But, I don't understand why this code is producing the different results when you use let or var in the for loop. Does it have something to do with the window object?

When var is used, all the console.log messages say 45.

When let is used, the console.log messages are 0 - 44 depending on which box is clicked.

You should be able to copy/paste and run the code below.

<!DOCTYPE html>
<html>
<head>
    <style type="text/css">
        section > div {
            height: 100px;
            width: 100px;
            background-color: red;
            float: left;
            margin: 3px;
            cursor: pointer;
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.29/browser.js"></script>
    <script type="text/babel">
        for(var i = 0; i < 45; i++){
            var div = document.createElement('div');
            div.onclick = function() {
                console.log("you clicked on a box #" + i);
            };
            document.getElementsByTagName('section')[0].appendChild(div);
        }

    </script>
    <title>Let Keyword</title>
</head>
<body>
    <header>
        <h1>Click on a box</h1>
    </header>
    <section></section>
</body> 
</html>
  • 3
    Don't they explain it in the video? –  Apr 04 '18 at 15:16
  • @CrazyTrain Nope. That's why I posted here. LOL. The other (duplicate) posts helped me see that this has to do with Closure. – Planet.Megan Apr 04 '18 at 15:19
  • Actually, this is also a good post here. It should be added to the list of other posts: https://stackoverflow.com/questions/34750447/let-keyword-and-closures – Planet.Megan Apr 04 '18 at 15:21
  • Maybe I misunderstood. I thought you were saying that the video showed both ways with `let` and `var` but then didn't explain why they behaved differently. –  Apr 04 '18 at 15:41
  • That is correct. The instructor only said that "this is a problem in JS" and the reason to use let was: " So instead of having our i being overwritten each and every time we go through the loop, we want to store this value with all of our divs." But, the instructor didn't explain this JS problem and the "overwriting" part in any kind of detail. I am not being critical of the video or the instructor. It seems like this course is more of an overview of the ECMA 6 additions and not meant to give full explanations. I am searching for more explanations. – Planet.Megan Apr 04 '18 at 16:27
  • After further reading, I see that, when using var, the value passed to i in the console.log statement is by reference. But, when using let, the value passed is by value (according to the second link above). So, when using var, after the for loop has finished, the reference points to "44" which is the last value. With let, the value is associated with the variable i. – Planet.Megan Apr 04 '18 at 17:00
  • JavaScript is always passed "by value". There are some reference types where the reference itself is passed by value, but that's not true for numbers. The issue here is simply that there's a single `var i`, which is scoped to the top of the script, so all the functions are "looking at" that same variable. Every time you mutate `i`, all the functions see the same mutation. With `let`, the scope of the variable starts *inside* the loop's block, so a new `i` is created on every iteration, and so there's a unique `i` paired with each function. –  Apr 04 '18 at 20:58
  • ...your loop is effectively [***like this example***](https://jsfiddle.net/1c0zh96y/), which should make it more obvious why they all see the same value. –  Apr 04 '18 at 21:01
  • @Crazy Train I was reading what was was on these two other pages. The first one says about halfway down the page: "This is not a bug, it's the way closures work. The logging function is a closure (or has a closure, as the term is used in both ways) containing a reference to the i variable. This is a reference and not a copy, ..." - - The other page in the answer by StepUp and Gurpreet Singh (with 395 votes) says: "Code above demonstrates a classic JavaScript closure problem. Reference to the i variable is being stored in the click handler closure, rather than the actual value of i". – Planet.Megan Apr 04 '18 at 21:51
  • @CrazyTrain The links to these two pages are here: https://blog.angular-university.io/really-understanding-javascript-closures/ and https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var-to-declare-a-variable-in-jav – Planet.Megan Apr 04 '18 at 21:51
  • @CrazyTrain Thanks for the code example. I will compare it to the original code. – Planet.Megan Apr 04 '18 at 21:55
  • The term "reference" is quite a bit overloaded unfortunately, so the context is important. Often when someone says *"...this function has a reference to `i`..."*, they just mean that it is within the scope of the function, so the function can *refer* to that variable. However, a "reference" can be much more than just the ability to refer to something; it can be an actual type that lets you *indirectly* refer to something. –  Apr 04 '18 at 22:54
  • Some languages, like JS, have types that are commonly called a *"reference type"*, which just means that you never actually hold the data directly, but there's an automatic reference through which you access the data. JS objects are that way. That's why if variable `a` is an object, and you do `var b = a`, then both `a` and `b` hold a *copy of the reference* to the same object, so mutating the object from `a` will be seen from `b`, and vice versa. –  Apr 04 '18 at 22:54
  • But then there are *"by reference"* languages. JS is not one of those. In those, it isn't just the data that is referenced, but it's the variable itself. So given the `a` and `b` example above, in a *"by reference"* language, if you then did `b = {foo:"bar"}`, this would also update the `a` object. This does not happen in JS, because it's only the object that is behind the reference, and not the variable itself, so in that code, you're assigning a new reference to a new object to `a`. –  Apr 04 '18 at 22:54
  • @CrazyTrain -- Thanks for that explanation of "reference". I am at the point where I have a lot to learn about JS, and sometimes I read/try to take in a lot that is above my knowledge level. But, the best thing I think I need to do is to keep coding and reading and asking questions. That makes your code example more important to explain this. I will read up more. – Planet.Megan Apr 05 '18 at 23:10
  • Yep, good approach. It's tough to grasp some of this just by explanations. Best of luck! –  Apr 06 '18 at 14:27

0 Answers0