I do not yet have a basic understanding of JavaScript closures;
I have a question regarding a specific situation that perhaps is also basic and common example:
Count from 1 to 3 in 3 seconds
See JSFiddle here: http://jsfiddle.net/nAh8x/
The code:
var i,
t;
t = 0;
// Case A
for( i=1; i<=3; i++ ) {
setTimeout( function() { log(i); }, t );
t += 1000;
}
// Case B
for( i=1; i<=3; i++ ) {
setTimeout( wrapper(i), t );
t += 1000;
}
function wrapper(i) {
return function() { log(i); };
}
// Log utility function
function log(msg) {
$('#log').append( msg + '<br />' );
}
Case A doesn't work.
It's clear to me why: every time the function inside setTimeout is called and accesses the i variable, its value has already reached 4.
Case B works.
When wrapper(i) is called it returns
function() { log(i); };
and the above return value (a function) is what goes inside setTimeout. What goes inside setTimeout is exactly the same as Case A
But this time, the i variable have been "frozen" with the value at the time of the call.
Why using the wrapper function let the passed value to be frozen?
That's not completely clear to me.
Closure is an environment which is created with variables scope and nested function by calling of outer function,
Every time the wrapper() is called there would created each different environment for below's function
function wrapper(i) {
return function() { log(i); };
}
Here is the i's value would be same as when wrapper() is invoked. Each time the i's value would be private for that particular environment which made by invoking wrapper() outer function.
The wrapper function has it's own i that is locally scoped to it.
This receives the value of the other i at the time wrapper is called.
It might be clearer if you rewrote it as:
function wrapper(notI) {
return function() { log(notI); };
}
The variable i used inside wrapper is the one the has been passed (as a copy) as the formal parameter to wrapper. It's not the same i as the one inside your for loop - you could rename that variable to anything you like and the code would still work.
It's frozen because it has the value it had each time wrapper was originally called.
Related
I have referred to multiple links for this concept but it is little bit tricky to wrap the concept around the head completely.
I was going through and example of it on https://www.w3schools.com/js/js_function_closures.asp
var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
add();
add();
add(); //Counter is 3
But isn't every time this is getting called counter is getting reinitialized to 0?
Can someone use table or something to help me understand every step here?
What add holds is returned function in the IIFE. (https://developer.mozilla.org/en-US/docs/Glossary/IIFE)
function () {counter += 1; return counter}
So calling add doesn't reinitialize counter.
var add = (function() {
var counter = 0;
return function() {
counter += 1;
return counter
}
})();
console.log(add());
console.log(add());
console.log(add());
var addHandler = function() {
var counter = 0;
return function() {
counter += 1;
return counter
}
};
const add = addHandler(); // return inner function
console.log(add());
console.log(add());
console.log(add());
In javascript, functions have their own execution environment.
And the execution environment is created when the function is called and disappears when execution is complete.
In the code above, the value in "add" becomes the new function returned after the IIFE function is executed.
In other words, the execution environment of the IIFE function has already been executed and disappeared.
However, the inner returned function is still looking at the parent function's variable "counter".
Previously, it was said that the environment disappears when the function is called. In this case, the remembering the environment of the parent function is called a'closure'.
IIFE is an immediate function.
Functions are declared and called when necessary in the form of "function name()".
The IIFE above will execute the function right away by declaring the function and wrapping it in "()".
I'm having trouble understanding why the first snippet below executes all five console.log's quickly, while the second snippet executes the console.log's one second apart.
I understand that a closure (aka a function + the scope in which it was declared) is needed to "close" over the value of i at various points in the for loop.
I understand that in the first snippet, the innermost function is immediately invoked, while the second snippet's innermost function is not immediately invoked.
And yet, it does not feel clear to me what is actually happening.
Some questions:
In the first snippet, is the innermost function executing over separate ticks?
In the first snippet, why does the innermost function execute so quickly?
In the second snippet, why does the innermost function execute over one second intervals?
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
(function () {
console.log(x)
})(i)
})(i),
i * 1000
)
}
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
return (function () {
console.log(x)
})
})(i),
i * 1000
)
}
Note: I do understand that using let makes this much easier, but I'm trying to understand this in terms of closures.
for (let i = 1; i <= 5; i++) {
setTimeout(
function () {
console.log(i)
},
i * 1000
)
}
This has nothing to do with the mechanics of closures. This is 100% caused by how functions work.
Now, let's tease apart the two different functions. For clarity I'm going to completely remove the for loop:
1:
var i = 1; // We simply hardcode `i` for this demo.
function a (x) {
(function(){
console.log(x);
})(i); // immediately call this function
// THIS IS THE MOST IMPORTANT PART OF THE CODE
// Yes, this space with no code at all at the end of
// this function is the MOST IMPORTANT part of the code.
// This absence of code represents "return undefined".
// All functions that return nothing returns undefined.
}
setTimeout(a(i),i * 1000);
Note: remember that a() returns undefined. So the setTimeout is actually:
setTimeout(undefined,1000);
"Helpfully", if you pass undefined to setTimeout it will gracefully accept it and not generate any errors.
It should also be obvious that you directly call console.log when calling a().
Now let's look at the other code:
2:
var i = 1;
function b (x) {
return (function () {
console.log(x)
}) // <--- note you are not calling the inner function at all
}
setTimeout(b(i), i * 1000);
Note that since b() returns a function setTimeout will call the function returned by b() (the one that calls console.log) after 1 second.
The difference here is less about how closures work and more about how setTimeoute() works. setTimeout will invoke the passed in function sometime after the time passed in. So you pass it a function:
setTimeout(someFunction, 1000)
And in a 1000 milliseconds or so it executes someFunction()
In the first example you are executing the functions before setTimout ever has a chance to by immediately calling someFunction(). By the time setTimeout gets around to it, it doesn't have a function to call -- just the return values of the function you already called. The functions are being called synchronously on the current tick.
You can think of it like passing a callback. If you pass a callback to a function like this someFunction(null, cb) it can execute it later with cb(), but if you pass someFunction(null, cb()) it will receive the return value of cb rather than cb itself. If that's a function it will call that.
In the second example you immediately execute the outside function, but return a function the setTimeout can call later. That is what it does, which is why this works as expected.
It is simple, but tricky :)
In first example, your creating and executing anonymous functions. Then you return undefined to the setTimeout. setTimeout will execute nothing. Thats why it executes quickly.
In second example, your creating and executing an anonymous function that creates another anonymous function and return it to setTimeout. Then setTimeout will execute it.
See my comments:
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
(function () {
console.log(x)
})(i) -> create and EXECUTE anonymous function (execute it right away)
})(i), -> create and execute anonymous function. returns undefined
i * 1000
)
}
for (var i = 1; i <= 5; i++) {
setTimeout(
(function (x) {
return (function () {
console.log(x)
})
})(i), -> create and execute anonymous function. returns a new function
i * 1000
)
}
I have been working through this article on closures: Understand Javascript Closures with Ease
The final example deals with a closure inside a for loop.
I understand why an IIFE is used to capture the current value of 'i' as 'j'. What I don't understand about this example is why there is a 2nd, inner IIFE wrapped around the return statement. (My comment is in caps in the code below).
The code seems to work just the same without the inner IIFE. See CodePen here.
Is this inner function required for some reason, or is this just an oversight by the author?
function celebrityIDCreator (theCelebrities) {
var i;
var uniqueID = 100;
for (i = 0; i < theCelebrities.length; i++) {
theCelebrities[i]["id"] = function (j) { // the j parametric variable is the i passed in on invocation of this IIFE
return function () { //<--WHY DOES THIS INNER FUNCTION NEED TO BE HERE?
return uniqueID + j; // each iteration of the for loop passes the current value of i into this IIFE and it saves the correct value to the array
} () // BY adding () at the end of this function, we are executing it immediately and returning just the value of uniqueID + j, instead of returning a function.
} (i); // immediately invoke the function passing the i variable as a parameter
}
return theCelebrities;
}
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0},{name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
var stalloneID = createIdForActionCelebs [0];
console.log(stalloneID.id); // 100
var cruiseID = createIdForActionCelebs [1];
console.log(cruiseID.id); // 101
var willisID = createIdForActionCelebs[2];
console.log(willisID.id); //102
The inner function, as you observed, has no practical effect. It doesn't make sense to use it.
It appears to be a holdover from the previous example in the article where a function was returned instead of a number.
I don't quite understand JS closures and I think it can solve my problem. here it is:
I have something like that :
$(document).ready(function () {
$("#buttonConfirm").click(function () {
popup_confirme();
});
});
function popup_confirme() {
var r = popup_modal();
}
function popup_modal() {
var int_val = 0;
$(".button").click(function () {
int_val = ($(this).val() == 'yes' ? '1' : '0');
});
return int_val;
}
I would like to get my int_val returned by the button click event. I need to get the 'r' value as 0 or 1. I know I should use closures, but I dont know how to do it. Thank you for your expertise !
You can't do this, it's impossible, for reasons unrelated to closures.
Your not calling the code that sets int_val, you're only defining the code, and saying "when .buttons are clicked, invoke this code". The code will not have been executed at the point you run return int_val, it will be executed at some point in the future when the button is clicked.
This block of code cannot logically work:
// First line run
var int_val = 0;
// Second line run
$(".button").click(function () {
// This line runs in the future, or maybe never, if the button isn't clicked
int_val = ($(this).val() == 'yes' ? '1' : '0');
});
// Third line run
return int_val;
If you want to communicate values back out of asynchronous functions, you should use promises:
function popup_modal() {
var dfd = $.Deferred();
$(".button").click(function () {
int_val = ($(this).val() == 'yes' ? '1' : '0');
// Allow int_val to find its way back to the calling code's `done` handler
dfd.resolve(int_val);
});
return dfd.promise()
}
The calling code will receive a promise object, which it can add callbacks to:
function popup_confirme() {
var r;
popup_modal().done(function (int_val) {
r = int_val;
}
}
I can't intuit beyond this point what you meant int_val to do up in your calling code.
A closure occurs when an inner function references something defined outside it. To illustrate:
function outer() {
var foo = 1;
element.click(function () {
// this function creates a closure on foo.
alert(foo);
});
};
What you seem to want done is that your int_val variable be accessible where both popup_modal and popup_confirme can get to it.
Many ways to do it based off your example, but something as simple as this can work:
(function () {
var int_val = 0;
var popup_modal = function () {
int_val = $(this).val() === 'yes' ? 1 : 0;
};
var popup_confirme = function () {
// your original code here doesn't really do anything
alert(int_val);
};
$('.button').click(popup_modal);
$('#buttonConfirm').click(popup_confirme);
}());
Technically all JavaScript functions are closures as they are objects with a scope chain attached to them. A closure is simply the combination of a function object and a scope (a set of variable bindings).
Scope is actually pretty simple really. Javascript uses lexical scoping which means that function are executed in the variable scope that was in effect when they were defined. Simply put, An outer function cannot read a value from an inner function unless is is specifically returned. An inner function can read all values declared in an outer function.
When most people talking about closures they are actually referring to the act of returning an item from an inner nested function to the outer function in which it has been defined.
e.g
// I am the outer function.
function outer (){
var outerVariable = "I am available to inner functions.";
// I am an inner function. I was declared in the scope of the outer
// function and as such all the variables declared in that scope are
// available to me.
function inner (){
// This will return => "I am available to inner functions." as we can
// read the outer declaration.
var innerReadValue = outerVariable;
// This will be available only to the inner function as it is
// not returned.
var privateVariable = "I am private";
// This will be available to the outer function as we are returning it
// on the next line.
var publicVariable = "I am available to outer functions";
// Make publicVariable public. This is what most people refer to
// when talking about closures.
return publicVariable;
}
// Read the inner functions publicVariable declaration.
// Returns => "I am available to outer functions"
var outerReadValue = inner();
}
In your example you are trying to get a value that was declared and not returned on the inner scope. As you should understand by now, this is invisible to the outer function so cannot work.
This can be rewritten as such:
// This is called an Immediately Invoked Function Expression. IIFE, It
// basically wraps your code in a function hiding all internal declarations
// from the global scope and then invokes it. You don't want to pollute the
// global scope.
(function(){
// Declare this outside so all functions can read it.
var int_val = 0;
// Declare this outside so all functions can read it.
var popup_confirm = function(){
// "int_val" is available here.
return int_val;
};
// Although your function runs automatically, we delay binding until
// the DOM is ready.
$(document).ready(function(){
$("#buttonConfirm").click(function(){
// Provide feedback. "popup_confirm" is available here
// since is declared in the outer scope.
return popup_confirm();
});
$(".button").click(function(){
// Set the value of int_val that has been declared in the outer
// scope.
int_val = $(this).val() === "yes" ? 1 : 0;
});
});
}());
Hopefully this makes it all a little bit more clear to you.
I have often see expressions such as:
(function () {
var x = 1;
...
}());
How do I interpret it? syntactically, this alone is a anonymous function definition.
function() {
...
}
what the () after that? and why put it in the enclosing ()?
Thanks
Exactly the same, except that it is being invoked immediately after being converted into a function expression.
// v-----first set of parentheses makes the function an expression
(function () {
var x = 1;
...
}());
// ^-----this set is used to invoke the function
Same as if you did:
var myfunc = function () {
var x = 1;
...
};
myfunc();
or (similar) this:
var returnValue = function () {
var x = 1;
...
}();
Get rid of the names, move the parentheses around, and you can see they're not that different.
The area where I most often find this useful is in callback functions. This notation can also used in cases where you need to include a variable in a callback function, but you need the variable state to not be affected by what goes on outside the function.
var someVal = 1;
setTimeout( (function(one) {
return function() {
alert(one); // alerts a 1 even 10 seconds after someVal++;
}
})(someVal), 10000);
someVal++; // the value in the setTimeout will remain the same as it is locked inside.
In this context, setTimeout takes a function that takes no arguments. So the question of how to pass in a value to that function is answered by creating a function that takes one argument that returns a function that takes 0 arguments.
I suggest anyone wanting to learn more about the power of this notation to play around with it in the Firebug JavaScript console. Once you wrap your head around this concept, you'll start to see areas where this powerful concept can be used.