14

I was looking at Mozillas developer site on javascript closure and they had this example of code.

  function makeAdder(x){
    return function (y) {
        console.log(y + " this is y")
        console.log(x + " this is x")
        return x + y;
        }
}
var add10 = makeAdder(10);
console.log(add10(2)); // 12

Now i understand the X attribute being set but what i dont get is how the scope of the y is being affected. I know its a return function but my brain went to mush trying to visualise how you could set a y when there was no ref to it. could someone explain?

5 Answers 5

16

makeAdder returns a function to which you can pass the y parameter. It is set at the time of invocation, as opposed to x which is set at the time of creation of the new function (at the time of the invocation of makeAdder).

For the case of this example, the output is equivalent to having written:

function add10(y) {
    return 10 + y;
}

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

Nothing new is going on here. The sample code is mainly trying to illustrate that a closure is being created for x.

So makeAdder, here, is aptly named: when you pass 10 to it, it gives you a function that will add 10 to everything you pass to that new function.

var add10 = makeAdder(10);
var add20 = makeAdder(20);

console.log(add10(1) + add20(1)); // 32

Surely, for the purpose of adding, it might be easier to just have a function that accepts two parameters and adds them. But this is not a lesson in adding, it is a lesson in closures.

A real world scenario might be something like this:

var buttons = document.getElementsByClassName('myButton');
for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = function() {
        alert('You clicked button ' + i);
    };
}

In the above code, i will have iterated through the entire set before any of the buttons are clicked. Therefore, all buttons will alert whatever buttons.length is. Instead, you could do the following:

var makeAlert = function(x) {
    return function() {
        alert('You clicked button ' + x);
    };
};

for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = makeAlert(i);
}

The difference here is that i is not being used when the button is clicked (which will be after the entire iteration), but it is used during the iteration, at a time when i will have a different value for each button.

Instead of creating a variable, makeAlert, you will often see this type of code being written as an anonymous function, invoked immediately. The code below is essentially equivalent to the code above:

for(var i = 0; i < buttons.length; i++) {
    buttons[i].onclick = (function(x) {
        return function() {
            alert('You clicked button ' + x);
        };
    })(i);
}
Sign up to request clarification or add additional context in comments.

8 Comments

I see, my brain is still trying to get it, im just trying to see how y is passed or set when there is no reference to it as add10(3) in my head says that your setting X not why?? This seems quite confusing :(
No, x is set to 10 in the call makeAdder(10). y is set to 2 in the call add10(2).
But shouldnt makeAdder(10, 2) do the same thing? or is what we doing essentially makeAdder(10).(2) ? thank you guys so much by the way :)
@mustafa: makeAdder(10, 2) calls makeAdder with two arguments, but it only accepts one. makeAdder(10)(2) (without the dot) calls makeAdder with one parameter (10) and then calls its return value with one parameter (2) and yes, that is what you are doing. If makeAdder was not returning a function, makeAdder(10)(2) would throw an error.
@mustafa: It's exactly the same as makeAdder(10)(2). makeAdder(10, 2) will not work here, because makeAdder only expects one parameter, and will disregard anything else. It'll still return the function to compute a result, not the result itself.
|
6

What you're asking for is a function that does something for you:

  function giveMeAFunctionThatBeeps(){
    return function () {
         alert('Beep!');
        }
}

var beeper = giveMeAFunctionThatBeeps();

beeper(); // beeps!

The actual giveMeAFunctionThatbeeps is just a factory that gives you a function that does what you want.

In the example they have provided, you're doing the same thing as the beeper but you're also passing in a value:

  function giveMeAFunctionThatBeepsANumber(x){
    return function () {
         alert('Beep ' + x);
        }
}

This returns a beeper (it's a factory remember), but the beeper alerts the value of x.

However, this value is set when you first create the beeper:

var beeper = giveMeAFunctionThatBeeps(5);

beeper(); // beeps 5!

The beeper is stuck beeping the value 5 now, and we can't do anything about it.

The next example is if you want to create a beeper that beeps any number:

  function giveMeAFunctionThatBeepsANumber(){
    return function (x) {
         alert('Beep ' + x);
        }
}

var beeper = giveMeAFunctionThatBeeps();

beeper(6); // beeps 6!
beeper(7); // beeps 7!

As now we're asking the factory to give us a function we can plug a number into.

Then lastly, the original example, is both of the above combined:

  function giveMeAFunctionThatBeepsANumber(x){
    return function (y) {
         alert('Beep ' + (x + y));
        }
}

var beeper = giveMeAFunctionThatBeeps(2);

When we create the beeper, we're passing in 2. Remember as above, we can't change this afterwards! It will always beep 2...

...but because it's a factory (preconfigured with value 2) returning a function that takes a parameter, we can customise it when we run it:

beeper(6); // beeps 8! because x was set when we created it, and y is what we pass in.

1 Comment

No worries, I had trouble with closures and I found just reading tons and tons of different explanations for the same thing helped :)
2

Functions can be seen as special objects that contain executable code as well as properties. Every function has a special [scope] property that represents the environment it was in when it was defined. If a function is returned from another function then this reference to the old environment is closed over by the new function in a "closure".

so when you call var add10 = makeAdder(10) what happens is that the returned function's x has the value 10 which is bound to it's scope, and the call console.log(add10(2)) prints 12.

Consider reading this article for visualizing what are closures. A more detailed explanation of closure could be found here.

Comments

1

The function makeAdder returns a function when it is called. This function that makeAdder returns accepts one parameter; which is called y.

The variable y exists only during the invocation of the function returned by the makeAdder. It is created each time is is called, and is destroyed when the function returns.

The variable x on the other hand is created when makeAdder is called, and persists due to the closure created by the function makeAdder returns. It will be destroyed when no more references to the function returned exists.

Comments

1

So add10 = makeAdder(10); is actually returning this function:

function(y) {
  console.log(y + " this is y")
  console.log("10" + " this is x")
  return 10 + y;
}

Then add10(2) is calling that function, replacing y with 2 everywhere:

  console.log("2" + " this is y")
  console.log("10" + " this is x")
  return 10 + 2;

4 Comments

Ok, but how do you know your targetting y, sorry to sound so much like a novice im justing trying to see how you would know you were accessing the right parameter, i think my problem is understaning returning functions as opposed to vars etc..
Well first think of replacing x with 10 everywhere, and assigning that function to add10. The first time you are calling makeAdded you are targeting the first function per se, and the second time you are targeting the 'second' function, the one with y (that was first nested but now assign to a var and then beeing called). You can console.log(add10) in Firebug to see your yourself after making the assignment.
So its a bit like writting makeAdder(10).(2) ? thank you guys so much by the way :)
Like makeAdder(10)(2) or makeAdder(10).call(null, 2). Think as makeAdder(10) as a function, because if returns one. In JavaScript you can assign a function to a variable, which is the case here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.