1

I've a few questions about closure. Sorry if it seems just another closure question, there are tons of posts and articles and I read so many, but I still have questions and couldn't find answers.

    var message = 'Hello!';
    document.getElementById('foo').onclick = function(){alert(message)};
    message = 'Goodbye!';

Here "Goodbye" will be alerted and the explanation is: "A closure does not merely pass the value of a variable or even a reference to the variable. A closure captures the variable itself!"

a. Please, can anyone explain to me what "capturing variable itself" means and how is THAT responsible for the message to be "goodbye" and not "hello"?

b. the function or the alert is the closure?

c. Also, am I correct with the following: the onclick is added to event table, that sends notice (when click occurred) to event queue, event loop checks call stack, its empty so the alert message is being added and executed. While all that is happening, JS engine already reached the line of code -> message = 'Goodbye!'; and this is why "Goodbye" is ultimately alerted?!

    for (var i = 1; i < 5; i++) {
      setTimeout(() => console.log(i), i*1000)
    }

vs 

    for (let i = 1; i < 5; i++) {
      setTimeout(() => console.log(i), i*1000)
    }

    for (var i = 1; i < 5; i++) {
      (function(i){
       setTimeout(() => console.log(i), i*1000)
      })(i)
    }
  • I always read "by the time the first setTimeout() runs, i is already at 5, and we don’t have any way to reference it" - but what is the reason that when first setTimeout() runs, the loop has finished? Has that actually to do with the event queue etc?!
  • I also always read the problem is that variable i isn't referenced. I just don't understand how referencing variable i has anything to do with setTimeout running after loop already finished.
  • when I use let, not var, I always read with let its block scoped, not function scoped so i doesn't become global.I understand. But could someone explain, what exactly happens - why/how is i not being global variable responsible for setTimeout NOT being called after for loop finished? I don't understand the connection.
  • Also, please can someone explain why with i*1000, i will not as I understand be always 5? Its because its outside of the closure?

Thank you so much and please if anything wasn't clear, let me know.

Omkar C.
  • 755
  • 8
  • 21
javascripting
  • 1,135
  • 4
  • 25
  • 46
  • 1
    _'...and the explanation is: "A closure...'_ - There's no closure in your example. That's just a matter of scope. – Andreas Jan 04 '20 at 11:23
  • [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Andreas Jan 04 '20 at 11:25
  • This helped me: https://johnresig.com/apps/learn/#49 – jefi Jan 04 '20 at 11:42

1 Answers1

2

Please, can anyone explain to me what "capturing variable itself" means and how is THAT responsible for the message to be "goodbye" and not "hello"

The function just alerts the value of the message variable.

When the function runs, that value is 'Goodbye!'

the function or the alert is the closure?

There is no closure in that example.

Also, am I correct with the following: the onclick is added to event table, that sends notice (when click occurred) to event queue, event loop checks call stack, its empty so the alert message is being added and executed. While all that is happening, JS engine already reached the line of code -> message = 'Goodbye!'; and this is why "Goodbye" is ultimately alerted?!

No.

  1. You assign 'Hello!' to the variable
  2. You assign the event handler
  3. You assign 'Goodbye!' to the variable
  4. The element gets clicked
  5. The event triggers
  6. The function is called

It isn't added to the stack until the click happens, so it won't be added between steps 2 and 3.

I always read "by the time the first setTimeout() runs, i is already at 5, and we don’t have any way to reference it" - but what is the reason that when first setTimeout() runs, the loop has finished? Has that actually to do with the event queue etc?!

setTimeout sets up a function to run in the future and doesn't block other code from running, so the loop keeps running, and changing i.

I also always read the problem is that variable i isnt referenced.

It's nothing to do with references.

I just dont understand how referencing variable i has anything to do with setTimeout running after loop already finished.

The relationship to i has nothing to do with setTimeout. The function you pass to setTimeout explicitly uses i. That's why it matters.

But could someone explain, what exactly happens - why/how is i not being global variable responsible for setTimeout NOT being called after for loop finished? I dont understand the connection.

Again, nothing really to do with setTimeout.

Each time you go around the loop you create a new function and pass it to setTimeout. That function uses i.

If i is scoped to the block instead of the containing function, then each time you go around the loop you get a different i variable (instead of the same i variable that you would get with var or a global).

Also, please can someone explain why with i*1000, i will not as I understand be always 5? Its because its outside of the closure?

No. It's because it is outside of the function passed to setTimeout so it is used immediately with the current value and not later after the value of i has changed to whatever it is after the loop has finished.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • `There is no closure in that example.` well technically, the function keeps a reference to it's parent scope. – Jonas Wilms Jan 04 '20 at 11:34
  • you said "The function just alerts the value of the message variable.When the function runs, that value is 'Goodbye!'" I know goodbye is alerted, but I was wondering why its goodbye and not hello? – javascripting Jan 04 '20 at 11:45
  • Also, you say: "Each time you go around the loop you create a new function and pass it to setTimeout. That function uses i." if I use var not let, I ALSO create a function on each iteration or no? If I do, then the for loop isnt finished so even if i is global, shouldnt I still get 0,1,2,3,4 ? – javascripting Jan 04 '20 at 11:51
  • @javascripting — "if I use var not let, I ALSO create a function on each iteration or no?" — Read the next paragraph. – Quentin Jan 04 '20 at 11:52
  • I did. I just cant understand how block scoped vs function scope is connected to the loop beeing finished before setTimeout is called – javascripting Jan 04 '20 at 11:55
  • @javascripting — It's the difference between having one blackboard (`i`) and changing what is written on it each time and having a new blackboard added to the wall every time you go around the loop with each slip of paper referring to a different board. – Quentin Jan 04 '20 at 11:57