15

So I'm new to programming and I'm trying to learn JS with the book Eloquent Javascript.

So far so good, until I reached an example with the following code

function makeAddFunction(amount) {
  function add(number) {
    return number + amount;
  }
  return add;
}

var addTwo = makeAddFunction(2);
var addFive = makeAddFunction(5);
show(addTwo(1) + addFive(1));

note: show is like alert, only it shows the variables on the screen of a JS console the tutorial has integrated.

The author says this is an example to show how lexical scoping allows to synthesise functions. Chapter here

What I don't understand is how addTwo and addFive, which supposedly are variables, can send parameters to the functions makeAddFunction and add, and more specifically, how does the function add knows that the parameter the variables are sending is the parameter number.

Thanks for your help guys!

Larry K
  • 47,808
  • 15
  • 87
  • 140
jsebcortes
  • 189
  • 9

6 Answers6

9

In javascript, a function is a first-class object, that is, it can be passed around, assigned to a variable, etc. The variables addTwo and addFive contain functions. Those functions are generated by the "factory" function makeAddFunction.

The functions that addTwo and addFive contain carry with them the scope that existed when they were created. That is, when addTwo, for example, was created, the parameter "amount" was 2. So addTwo, in essence, is the following function:

function addTwo(number) {
   return number + 2;
}

When someone calls addTwo(), it's not passing anything back to makeAddFunction. MakeAddFunction has already run and is finished. However, the scope created within makeAddFunction (in which "amount" equals 2) lingers in the addTwo function.

Jacob Mattison
  • 50,258
  • 9
  • 107
  • 126
  • Fantastic! I was cross-eyed and drooling over this example (not yours, the one from Eloquent JavaScript), but your explanation has made it crystal-clear! Yours is the first explanation I saw (and understood) which mentioned the fact that amount gets "baked in" when the "function-maker" is building the internal function that it returns. Thank you!!! – mbm29414 Sep 14 '11 at 18:13
  • I really had to mull it over for a few minutes to understand it but this is the clearest explanation here. It helped me to think of `makeAddFunction()` like a constructor, in that it returns new instances of `add()`. – user110857 Sep 27 '13 at 14:32
8

addTwo and addFive are variables -- but they're function variables. Look at typeof(addTwo) -- it's a function. It's like if you did this:

var addTwo = function(x) { return x + 2; };

It's the same as this:

function addTwo(x) { return x + 2; }

(Edit: As Šime pointed out, they aren't exactly the same. See here for an explanation of the difference between the two.)

The example will hopefully make sense once you understand that. You can even do weird things like this, declaring an anonymous function and invoking it right away:

var seven = function(x) { return x + 2; }(5);

Which is literally, at the physical machine code level, the exact same as: Which is equivalent to for all purposes relevant to this question:

function addTwo(x) { return x + 2; }
var seven = addTwo(5);

Edit:

Perhaps a less confusing "prequel" to this is the following:

function makeTheAddTwoFunction()
{
    return function(x) { return x + 2; }
}

var addTwo = makeTheAddTwoFunction();

This is silly, but serves to illustrate functions that make functions. Of course, that sort of function usually will accept arguments so that it can make different functions each time, but there you go.

Ian Henry
  • 22,255
  • 4
  • 50
  • 61
  • 4
    @Ian The first two code lines are not equivalent. They are only *almost* the same. – Šime Vidas Nov 07 '10 at 01:12
  • @Šime Can you explain the difference? Both define the symbol `addTwo` in the current scope and set its value to the same function. I have always treated these as interchangeable, perhaps to my detriment. – Ian Henry Nov 07 '10 at 01:16
  • Sorry, the examples given are NOT the same. You're comparing assignment of a variable to a function with giving a function a name. They are NOT the same! They may have different values for *this*; the function assigned to a variable can be re-assigned, function not so much. **Remember** that this SO Q is about the fine points of the language, so these issues matter. – Larry K Nov 07 '10 at 01:21
  • 3
    @Ian The first one is a *VariableStatement*. The other one is a *FunctionDeclaration* (which is not a *Statement*). Function declarations are evaluated before any other statements in the current execution context. This means that a function defined via a declaration can be executed even if the call occurs before the declaration (in the code), like so: `foo(); function foo() {}`. This cannot be done with a function variable: `foo(); var foo = function() {};` (produces an error) – Šime Vidas Nov 07 '10 at 01:21
  • @Ian I *think* what Šime is getting at is that "function name() {}" hoists bother the declaration *and* definition to the top of the scope, while "var name = function () {}" hoists the declaration, but *not* the assignment. Also, "function name() {}" sets the function's name properaty, where var anonymous = function () {} doesnt. – Angiosperm Nov 07 '10 at 01:24
  • @Šime Thanks; I've edited the post explaining the difference. @Larry I'm not quite sure what you mean. Functions can be reassigned just like variables, and the value for `this` only depends on how it's invoked -- the same invocation of both of these wouldn't give different values for `this`, would it? – Ian Henry Nov 07 '10 at 01:26
6

I think the key to understanding that example is understanding that functions can return other functions (just like any other variable). Documenting that code will go a long way in helping understand that concept.

/** 
 * Creates an adder function
 * @param {number} amount Amount to add
 * @return {function}  Method that adds 'amount' to its argument. 
 * See the documentation of add for its signature
 */
function makeAddFunction(amount) {      
  /**
   * Everytime makeAddFunction is called, a new instance of add  is created
   * (and returned) that holds on to its copy of 'amount' (through the closure)
   * @param {number} number value to add to 'amount'
   * @return {number} 'amount' + 'number'
   */
  return function add(number) {
    return number + amount;
  };
}

// addTwo now is a reference to a function that when called
// adds 2 to whatever is passed in
var addTwo = makeAddFunction(2);
// addFive Adds 5 to its argument
var addFive = makeAddFunction(5);
// addTwo(1) = 3, addFive(1) = 6, therefore, output is 9
show(addTwo(1) + addFive(1));
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
3

Re: What I don't understand is how addTwo and addFive, which supposedly are variables, can send parameters to the functions makeAddFunction?

addTwo and addFive are variables. But their values are not simple scalars (numbers, strings, etc). Rather, their values are functions. Since their values are functions, it is fine to invoke those functions. Eg, addTwo(1)

Re: and more specifically, how does the function add knows that the parameter the variables are sending is the parameter number?

The function add is calling its first parameter number. So later, when you call the function via a variable, eg, addOne, the first parameter given to addOne becomes number.

ps If you're thinking to yourself, "Self, this is pretty tricky!" Then you're right--and that's the entire purpose of the example, to show something tricky. How often you'll use this technique may vary from never to every so often.

Larry K
  • 47,808
  • 15
  • 87
  • 140
0

The best way to think of a piece of code like this is to substitute values and interpet in your mind

// when this one is invoked
var addTwo = makeAddFunction(2);

// makeAddFunction
// becomes something like
function makeAddFunction(2) {
  function add(number) {
    return number + 2;
  }
  // return a function, that adds
  // 2 to every number it gets
  return add;
}

// therefore this function call
// will add 2 to 1 and return 3
addTwo(1);
gblazex
  • 49,155
  • 12
  • 98
  • 91
0

As always, here are the Jibbring notes on JavaScript Closures. It discusses scopes, execution contexts, variable/property resolution, etc...

While JavaScript closures are lexical, execution contexts (which may contain properties) are bound (think Python or Ruby) and not just "free variables" (as is the case with C# or Scala). This is the reason why new variables can only be introduced in new function scopes. (Modern Mozilla implementations introduce let).