1

In my attempt to understand a very specific aspect of closure in javascript, I felt compelled to illustrate it with an example. This is pulled from MDN's explanation of closure:

function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

And this example is touched upon here, but I don't think it resolves my own personal confusion, although my confusion is also related to the value of y.

My question is when add5(2) returns function(y), how does it determine the value of y when y is not explicitly assigned anywhere within or outside of makeAdder(x)? Also, is add5(2) = makeAdder(5)(2)? And if so, how can this function execute when makeAdder(x)(y) is not defined in this example? Also, is there a way that describing it as such might help clarify this issue for someone who's having a hard time internalizing the logic behind closure? It appears as if add5(2) assigns 2 to y, but there's no clear way for me to trace this. Any help is much appreciated. Thank you!

Community
  • 1
  • 1
Quilty Kim
  • 455
  • 1
  • 4
  • 18
  • 2
    `y` is declared the same way as `x`, as an argument. The first time the makeAdder function is called it returns another function, the function where `y` is used as an argument, and that's passed in the second call that is being made to the returned function – adeneo Jul 13 '14 at 21:04
  • This is an example of [*Currying*](http://en.wikipedia.org/wiki/Currying), named after Haskell Curry, not the food. I guess "Schönfinkel–ing" was too much of a tongue–twister, or Schönfinkel was the wrong nationality to be recognised in computing. ;-) – RobG Jul 13 '14 at 23:41

3 Answers3

2

One way to look at this is that

var add5 = makeAdder(5);
var add10 = makeAdder(10);

is essentially equivalent to

var add5 = function(y) {
  return 5 + y;
}
var add10 = function(y) {
  return 10 + y;
}

Perhaps this helps?

NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

The variable "y" is the parameter of the function returned by a call to "makeAdder". It's value is not set in "makeAdder" because that wouldn't make sense; the whole point is to create a new function that will add a given value ("x") to a parameter ("y").

The returned function takes one argument, "y". When, after calling "makeAdder", code calls the function returned and so passes in a value for "y", the final addition (5 + 2 or whatever) is carried out.

Function call syntax (the parenthesized argument list) is evaluated left-to-right, so

makeAdder(5)(2)

is the same as

(makeAdder(5))(2)

meaning,

call the 'makeAdder' function with the parameter 5, and then when that returns treat its return value as a function reference and call that function with the parameter 2.

Pointy
  • 405,095
  • 59
  • 585
  • 614
1

My question is when add5(2) returns function(y), how does it determine the value of y when y is not explicitly assigned anywhere within or outside of makeAdder(x)?

The function returned by makeAdder is:

function(y) {
  return x + y;
}

where x has already been assigned the value 5.

So there is your y. It's inclusion as a formal parameter in the function expression is effectively the same as declaring it with var, x is initialised the same way in makeAdder.

Also, is add5(2) = makeAdder(5)(2)?

Yes, though I think you meant == (equals), not = (assignment).

And if so, how can this function execute when makeAdder(x)(y) is not defined in this example?

makeAdder returns a function, so the second set of parenthesis causes it to be called with whatever value is provided (including none):

makeAdder(5)(2) // 7

is the same as:

var foo = makeAdder(5);
var bar = foo(2);

the only difference being that in the second case, the intermediate result is stored as foo before being called.

Also, is there a way that describing it as such might help clarify this issue for someone who's having a hard time internalizing the logic behind closure?

The real power of a closure is that a function can return another function that continues to have the same scope chain it had when it was created, so that it has exclusive access to local variables of all the execution contexts on its scope chain (other than global variables, they aren't exclusive) after those functions have finished executing. Complex inheritance structures can be created with closures (not recommended though).

It's this persistence that makes a closures really useful, and not just scope chain resolution.

RobG
  • 142,382
  • 31
  • 172
  • 209