Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning functions in javascript, understanding scope & closures

Tags:

javascript

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?

like image 463
mustafa Avatar asked Dec 13 '11 10:12

mustafa


People also ask

What is the scope of return statement?

A return statement is used to end the execution of the function call and “returns” the result (value of the expression following the return keyword) to the caller. The statements after the return statements are not executed. If the return statement is without any expression, then the special value None is returned.

How does the return function work in JavaScript?

When a return statement is used in a function body, the execution of the function is stopped. If specified, a given value is returned to the function caller. For example, the following function returns the square of its argument, x , where x is a number. If the value is omitted, undefined is returned instead.

What is the scope of JavaScript functions?

Scope in JavaScript refers to the current context of code, which determines the accessibility of variables to JavaScript. The two types of scope are local and global: Global variables are those declared outside of a block. Local variables are those declared inside of a block.

What happens when a function is returned?

A return statement ends the execution of a function, and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can return a value to the calling function. For more information, see Return type.


2 Answers

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);
}
like image 161
David Hedlund Avatar answered Nov 08 '22 09:11

David Hedlund


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.
like image 36
NibblyPig Avatar answered Nov 08 '22 11:11

NibblyPig