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?
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.
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.
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.
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.
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);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With