1

The closure rule is: functions are executed using the scope chain that was in effect when they are defined.

In the setTimeout callback function below, x is not yet in scope at the time of definition. Therefore, the program should print undefined, but it prints 7, why? what am I missing?

var foo = function () {
    setTimeout(function (){
        console.log(x);
    }, 3000);
};

var x = 7;
foo();

Or, is it because the above code is exactly same as the below?

var x = 7;

var foo = function () {
    setTimeout(function (){
        console.log(x);
    }, 3000);
};

foo();
cmutex
  • 1,478
  • 11
  • 24
  • `x` and `foo` are in the same scope, and **when `foo` executes**, `x` is already defined, so logged fine. – Passerby Dec 25 '13 at 03:17
  • `x` is defined in first case before foo() runs and needs it. Try this http://jsfiddle.net/Yf76N/ – charlietfl Dec 25 '13 at 03:17
  • They are the same. The javascript interpreter do not care about the order of the variables definition. – eliuhy Dec 25 '13 at 03:18
  • 1
    This stackoverflow answer is very good and explains that x is an expression and is not evaluated until the function is executed. http://stackoverflow.com/a/3887590/584663 – Bill Dec 25 '13 at 03:19
  • Passerby, i disagree because functions are executed using the scope chain that exists at definition and not at execution/call. – cmutex Dec 25 '13 at 03:22
  • @user3124390 `foo` is a _function expression_, and even if it's a function, it's still under the same scope as `x`: http://jsfiddle.net/Yf76N/1/ – Passerby Dec 25 '13 at 03:25

1 Answers1

3

x is not yet in scope at the time of definition

This is not true. The reason is hoisting. Basically, JavaScript will move any var or named function to the top of the containing scope. So what you actually have is something more like this:

// these variables are hoisted
var x;
var foo;

// then the variables are assigned.
foo = function () {
    setTimeout(function (){
        console.log(x);
    }, 3000);
};

x = 7;
foo();

Read more on hoisting here.


Also, this is accurate:

functions are executed using the scope chain that was in effect when they are defined.

But your interpretation is not accurate. They have access to the scope in which they were defined, but not at the point they were defined. Variables can have values that change over time, and the functions declared in those scopes will use those up to date values from that scope. There is no time machine.

So when the nested function executes, foo is 7 because in that scope, at that moment, foo really is 7.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • are variables hoisted too? are you sure? can u please give reference. – cmutex Dec 25 '13 at 03:32
  • the link explains it all. tnx for sharing. – cmutex Dec 25 '13 at 03:37
  • @user3124390 I think the point here is not hoisting, but that "have the same scope at which it's defined" does NOT equals to "have the same value/status/whatever of _every variable/function/whatever_ when it's defined". – Passerby Dec 25 '13 at 03:38