1

Disclaimer: This question is purely curiosity driven and has to do a lot with how the javascript works.

I understand why the following code works. Due to closures, foo has access to the scope where a resides. This makes sense.

var a = 10

var foo = function(){
console.log(a);
}

setTimeout(foo,1000)

However, i wonder why the following also works (explained right after).

var a = 10
setTimeout(function(){
console.log(a);
},1000)

The function is defined in the argument of the function receiving it and essentially was never a closure to the scope that contains a. We know that when a function receives an argument, it creates a local variable for that argument so for example

var outerVar="5"

var bar = function(a){
//implicitly, var a = outerVar happens here
console.log(a)
}

bar(something);

So following that logic, the function passed to setTimeout couldnt have access to a and yet it does.

Im suspecting that when a function is defined in the argument space what happens is, it realy is defined before being assigned as an argument but have no proof of that. Any pointers highly appreciated.

Thanks a bunch.

Return-1
  • 2,329
  • 3
  • 21
  • 56
  • Your problem is with "The function is defined in the argument of the function receiving it and essentially was never a closure to the scope that contains a." This is not true. The definition of a function is where the closure over 'a' happens. And this is in the same scope as 'a'. – bhspencer Mar 04 '18 at 15:41
  • @bhspencer Yes but where exactly does the definition actually happen? I rephrased the question to display what i mean. Take a look at this: https://stackoverflow.com/questions/49106298/callback-definition-closure-issue – Return-1 Mar 05 '18 at 08:37
  • Possible duplicate of [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Return-1 Mar 12 '18 at 08:06

2 Answers2

2

It's not exactly closure, but it's close.

Strictly speaking, closure is when a variable's scope ends, but is still enclosed in an inner function that still lives on:

function createTimer() {
  let counter = 0;
  return function() {
    return counter++;
  }
}

const timer = createTimer(); // function() { ... }
console.log(timer(), timer(), timer()); // 0, 1, 2

The function in which counter is defined has returned, the scope ended, and under normal circumstances, counter should have died and garbage collected. But the inner function returned from createTimer() still has a reference to it, from the enclosed scope, that is a closure.


In JavaScript, every function has access to all of the scopes of all of its ancestors, this is what you're seeing here.

The function passed to setTimeout() has access to a because a is defined in the scope around it.

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308
  • This is a correct explanation of closures, true. What im challenging however is the following. Imagine that setTimeout has its own local variable 'a' equal to 50 . In practice, both my scenarios, A and B will print out 10. But i would expect scenario B to print out 50 given that its enclosed scope as you mentioned is that of setTimeout and not the global one. It seems to me like i get the general idea behind closures but when a function is defined in the parameter space it would appear to me that this function is really defined in the function that its beeing passed on, not outside. – Return-1 Mar 04 '18 at 16:01
  • But your `setTimeout` callback doesn't accept any parameters, there are also no variables named `a` defined within the function body (if there were, they would have *shadowed* the `a` from the enclosing scope). – Madara's Ghost Mar 04 '18 at 16:32
0

When you look at a javascript code and see how it works, the best way according to me is first understand the javascript engine how it works.

First it traverses the code and assigns all the variables to the scope and further more in the second trace it assigns the values based on the scopes.

So in your first code, The engine first traverses and assigns var a to global scope, var foo as global scope, Then when setTimeout runs it calls foo function and logs the value of a as that of the global a as it doesnt have any local “a” so checks the lexical scoping.

In your second code,

Var a is again global scoped and no other declaration this time. In second traverse it assigns the value 10 to a and interprets the settimeout and prints the value

In your third code, Same as the second one except the fact that instead what “foo” was giving to the settimeout function, you wrote your callback function then n there itself.

By the time l it executed the setTimeout, Each of your codes have the value for “a” in the global scope that they are accessing.

Yash Kumar
  • 13
  • 1
  • 7
  • Sure thing, but the question is, in my second scenario, does the function look for a first in the context of setTimeout and then in the global scope? I would expect this to be true but its not. – Return-1 Mar 04 '18 at 16:05
  • Why not? Just add another variable inside setTimeout as var a = 50; and check for the answer. It will print 50 as it now has a local variable a there – Yash Kumar Mar 04 '18 at 16:18
  • Thats what i thought too. You'd be surprised. Look here https://stackoverflow.com/questions/49106298/callback-definition-closure-issue. I had to rephrase the question – Return-1 Mar 05 '18 at 08:36
  • If you put a debugger just before the callback, you will see there is no closure being formed. And the function that you supplied as argument is local to the function. – Yash Kumar Mar 06 '18 at 07:48