1

I was not getting how a closure variable gets attached to function ([[Scope]]) when making a Web API request like for timer (serTimeout).

function fun() {   
    function log() {console.log(callme) }; 
    console.dir(log); 
    setTimeout( log, 10000);
    const callme = "hi iam"
  }
fun()

enter image description here function log gets access to variable callme when const do not get hoisted.

My thinking is that fun() is called , it is pushed to call stack , function log is then sent to WebAPI timer function , in the mean time fun gets run and sets callme variable in its execution context. Once Timer is over , fn log is pushed to callback queue and event loop after checking if call stack is empty pushes log to callstack for execution. I am not able to get the idea when callme gets attached to closure [[Scope]] of function log

Bhupendra
  • 1,196
  • 16
  • 39
  • `[[Scope]]` is just a reference to the execution context of the parent function. And as you said, *callme* got added to it (also it does get hoisted, just differently) – Jonas Wilms May 20 '20 at 06:31

1 Answers1

2

IMHO, hoisting is a really bad concept that just happens to be useful. It leads to minunderstandings such as yours. The real way the interpreter works is something like my answer to this related question: JavaScript function declaration and evaluation order

For your specific example, you mention:

when const do not get hoisted

This is not really true. Of course, hoisting does not really exist in the language, it is just a concept programmers created to explain how the language behaves. Let's see how your code is interpreted when we split the parsing into two phases: compilation and execution:

function fun() {   
    function log() {console.log(callme) }; 
    console.dir(log); 
    setTimeout( log, 10000);
    const callme = "hi iam"
  }
fun()

Compilation phase

  1. OK, we have a function definition fun, let's parse it's body
  2. OK, we have a function definition log, let's parse it's body
    1. OK, we're logging a variable callme. Note the variable we are using
  3. We want to call log after 10 seconds, Note the function setTimeout is using
  4. We define a constant callme

Execution phase

  1. OK, we are calling fun()
    1. We are declaring a function log(), create an instance of it
    2. We output the definition of log
    3. we are calling setTimeout(), find a variable/function called log - found it, add log to event queue
    4. Set the value of callme to "hi iam" (note that values cannot be set in compilation phase because it may involve executing code for example if we do const x = (1).toString(), const just means we cannot set the value outside of initialisation)
    5. End of function call, we detect that callme is used in a closure, attach it
  2. 10 seconds pass by, OK event loop detects timeout, call log()
    1. We need to log callme - found it in a closure, log it.

This is how callme gets pulled into foo's closure. If you insist on using the hoisting terminology you can say that if there is a closure then const gets hoisted.

But you don't really need to know all the corner-cases of when hoisting happens and when it does not if you have as your mental model this two-phase interpretation. I strongly suggest reading the answer linked above to get a better understanding of how it works.

slebetman
  • 109,858
  • 19
  • 140
  • 171
  • it is great explanation , thanks a lot it makes clear understanding now. Just one query since callme variable is not set during compilation phase and in execution phase step3 , using setTimeout fn forces log function to move from JS environment to webAPI world where timer exist and then callme is set to "hi i am" and fun() is removed from callstack. So how log has access to callme in execution phase step 2 – Bhupendra May 20 '20 at 11:55
  • As long as there's a closure a function or variable is not removed from the stack. Instead it is referenced counted and will be deleted eventually by the garbage collector. See my answer to this question for a more detailed explanation of the memory model for closures: https://stackoverflow.com/questions/26061856/javascript-cant-access-private-properties/26063201#26063201 (it's rather unfortunate that some of my most detailed answers were written as tangents to questions that are not directly about that topic making them hard to find even for me) – slebetman May 20 '20 at 12:35