5

This is from How do JavaScript closures work?. The first answer makes zero sense to me and I can't comment on it. It is extremely frustrating

function foo(x) {
  var tmp = 3;
  return function(y) {
    alert(x + y + (++tmp));
  }
}
var bar = foo(2); // bar is now a reference to the closure returned by foo
bar(10);

What does this mean? Where does the y variable come from?

Community
  • 1
  • 1
Jessica Shu
  • 256
  • 3
  • 12

3 Answers3

4

For where the variables come from:

function foo(x) {       // x introduced
  var tmp = 3;          // tmp introduced
  return function (y) { // y introduced
    // Can access all variables in scope, as introduced above.
    // However, ONLY x and tmp are closed-over as y is just a parameter
    // to the inner function.
    alert(x + y + (++tmp));
  }
}

var bar = foo(2);  // 2 is value for x
bar(10);           // 10 is value for y

Now, looking a bit deeper:

foo(2) returns a new function-object (the inner function) which is bound to two variables (x which currently has the value 2, and tmp which currently has the value 3).

Then bar(10) runs that function-object passing in 10 (which is then the value of y).

Calling bar(10) repeatedly will result in different values as a closed-over variable tmp is re-assinged (++tmp) during the function invocation.

Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120
user2246674
  • 7,621
  • 25
  • 28
  • okay thanks! for some reason I didn't get the concept of a function returning another function – Jessica Shu Jun 30 '13 at 22:42
  • @JessicaShu Not all languages have it - but once you see it, you can never forget it :D A big concept in JavaScript is that functions are just objects and can be passed around like any other value. A prominent result of this is closures as a function can be invoked from a scope other in which it was defined - I'm not sure that closures can exist without this property, although I'm not a theoretical language expert. – user2246674 Jun 30 '13 at 22:43
  • @Jessica: Such functions are called *higher-order functions*. http://en.wikipedia.org/wiki/Higher_order_function – Felix Kling Jun 30 '13 at 23:02
3

You need to distinguish between variables (a name for a piece of memory containing information) and parameters (placeholder for a variable to be passed into a function). (Actually it's called a formal parameter in the prototype of the function and an actual parameter when used in the function body.) So y is not an existing variable but a placeholder for a variable (or value) to be passed in.

You then need to understand that var func = function(){} turns func into a reference to an anonymous function (a function without a name). A simplified example would be:

var func = function (y) {
   alert(y);
}
func("hello");

You can work up from that. Everything else is just the same principle applied in a way of nesting.

zany
  • 881
  • 1
  • 7
  • 16
  • Why does there *need* to be a distinction? (They are both variables in JavaScript and behave darn-near identically - as can be seen the `x` "parameter" is used as a "variable" in the closure.) – user2246674 Jun 30 '13 at 22:49
  • There's not much difference. Both are names for places in memory, one is declared as part of a parameter list the other with a variable declaration statement in function body. The parameter variable gets assigned implicitly when an argument was passed for it, but from then on they work exactly the same. *`y` is a placeholder for a variable to be passed in* is definitely wrong. – Bergi Jun 30 '13 at 22:51
  • The term **variable** is really ambiguous here. You are likely thinking about a value somewhere in memory. But when this value gets passed as an argument it's original name is aliased (to the name of the parameter). It's actually the very same variable (ignoring the underlying pass-by-value mechanism). So there is never a variable `y` is just the name for what gets passed in. – zany Jun 30 '13 at 22:55
  • That is presuming implementation details (which are, unlike the JLS, not discussed in the ECMAScript specification). Using such terminology is not required to explain the behavior in JavaScript. A variable is simply a *name* (perhaps one of many) for a particular value. (The other behavior is explained by noting that variables are both mutable, variables belong to execution scopes, and that objects are mutable.) – user2246674 Jun 30 '13 at 22:57
  • 1
    FWIW, variable definitions and parameters both create bindings in the execution environment, so eventually there is no difference between them. For more detailed info, have a look at the spec: http://es5.github.io/#x10.5. – Felix Kling Jun 30 '13 at 22:59
0

foo is returning a function, which takes one argument called y.

So, when you call foo you get a function back, which you can execute whenever you like with an argument, which becomes the value of y.

Notice that the returned function is anonymous, but as foo returns it, you can effectively bind the function to a variable. Here, foo is being called, and the return value is being assigned to bar.

Now, you may ask "well, if the function return has the argument y, and I call bar(10), now y is given the value 10, but now what's x?

Well, x already has a value, which it got when foo was first called. Here's a "workflow" representation.

  1. A function called foo is defined, which takes one argument x. It returns an anonymous function which takes one argument called y.
  2. The function foo is called with a value of x equal to 2, and it's return value is bound to bar. bar is now a reference to the anonymous function, inside which all values of x are equal to the value of x foo was called with, i.e. 2.
  3. When the anonymous function bound to bar is called with bar(10), the argument y is given the value 10. bar executes the following

    alert(2 + 10 + (++tmp));

So you might ask now, "what's tmp then"? Well, that should be reasonably straightforward to deduce if you followed the above. When the anonymous function was returned from foo, any references of variables local to were bound to the values foo had a

Alex
  • 9,313
  • 1
  • 39
  • 44