This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I am confused why the following code snippet has (i) at the end of it:
for (var i = 0; i < 10; i += 1) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 1000);
})(i);
}
Ive seen it in production code Ive worked on--I just can intuit why it's necessary.
You are defining an inline function, so you could force the i parameter to be in the local scope at the time of the execution of the console.log statement. By adding the parameter, you are creating a self executing function. Similar would be the following statements, which might be better to read...
function logmeWithTimeOut(value) {
setTimeout(function() { console.log(value); }, 1000);
}
for (var i = 0; i < 10; i++) {
logmeWithTimeout(i);
}
Though I might prefer
function logmeWithTimeout(value) {
console.log(value);
}
for (var i = 0; i < 10; i++) {
setTimeout(logmeWithTimeout.bind(undefined, i), 1000);
}
It forces the i to be in local scope, otherwise your log would print only 11
Because you are defining a function inside the parenthesis, and then you are calling it passing i as parameter.
If you didn't put the (i) there, you would just define a function but never call it.
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
What is the (function() { } )() construct in JavaScript?
(28 answers)
Closed 7 years ago.
I was having an issue where I was setting up a bunch of timeout calls and I wanted the timeout function to reference the element in the current loop.
This is what the result looked like:
var createTimedMessages = function(arr, collection){
var timeLimit = 2000;
for(var i = 0; i<arr.length; i++){
let el = arr[i];
collection.push(el);
$timeout(function removeElement(){
collection.removeMatch(el);
}, timeLimit);
}
}
but I realized that this wouldn't work with some slightly older browsers because of lack of support for the let keyword. What is a good workaround?
Note: This is in angular, hence the $timeout rather than setTimeout.
Use a IIFE:
var createTimedMessages = function(arr, collection) {
var timeLimit = 2000;
for (var i = 0; i < arr.length; i++) {
(function(el) {
collection.push(el);
$timeout(function removeElement() {
collection.removeMatch(el);
}, timeLimit);
})(arr[i]);
}
}
Self-executing functions should solve the problem:
(function(el, timeLimit) {
$timeout(/* your code */);
})(arr[i], timeLimit);
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
Here's a simplification of my JS program. mylist is an array of strings and MyAsync is a function that takes an object and arranges for the supplied callback to be called at a later time.
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
MyAsync(mylist[myindex], function () { alert(myindex); });
}
When there's ten items in mylist, the result is two alert messages each showing "10". Okay, it's clearly using the value of myindex after the loop finishes. So I make a slight change...
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
var copyindex = myindex;
MyAsync(mylist[myindex], function () { alert(copyindex); });
}
Now, each alert shows "9".
How do I please arrange for the callback function to know what myindex was at the time MyAsync was invoked?
Asynchronously, billpg.
Yeah, as the comments and not making functions in a loop for the reason you are experiencing.
We can use a recursive function instead :
var len = mylist.length;
function asyncLoop(index) {
MyAsync(mylist[index], function () {
if(index < len) {
asyncLoop(++index);
}
});
}
asyncLoop(0);
As comments , - firing them all off at the same time* ( *- quick as a loop can run ). and keeping track of the array count ...
function asyncDo(index) {
MyAsync(mylist[index], function () {
/* we have access to the array index here */
console.log(index);
});
}
for ( var i=0, len=mylist.length; i<len; ++i) { asyncDo(i); }
You can use closures to do this: here is some code that I think demonstrates what you want, printing out 0 .. 9.
var funcs = [];
for(var i = 0; i < 10; i++){
funcs.push( (function(j){
return function(){
console.log(j);
};
})(i));
}
funcs.forEach(function(f){
f();
});
The idea is that in returning a function to be added to the list, the value of i is captured when that function was constructed from the parameter to the outer function.
Here's an SO post that helped me with this: JavaScript closures vs. anonymous functions
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 9 years ago.
Consider this
fs=[];
for(var i = 0; i < 3; i++){
fs.push(function(){
return i;
});
}
console.log(fs[0](),fs[1](),fs[2]())
I thought that i would be in the closure of the function so that this would print "0 1 2", but nope... it prints "3 3 3".
Why doesn't this work? And is there any way to make this work?
You are actually pushing three instances of the same anonymous function into your 'fs' array. Then your log statement calls that function three times. At the time you are calling it, the loop has completed and the value of 'i' within the closure is 3, so that's what is returned.
I'm not sure what you mean by "work", but maybe something like this is what you mean:
fs = [];
function closureFunc(myVal) {
return function () {
return myVal;
}
}
for (var i = 0; i < 3; i++) {
fs.push(closureFunc(i));
}
console.log(fs[0](), fs[1](), fs[2]());
This creates three separate closures where the function you are pushing has the scope of the declaring function "closureFunc". Within those closures the myVal is set to the value that was passed in.
Javascript doesn't have a notion of block scope, it only has function scope. Hence the placement of the var i is meaningless in terms of lifetime. It may as well have been the first line in the method.
In order to fix this you need to declare a new scope that holds a separate i value
fs=[];
var makeFunc = function(j) { return function() { return j; } }
for(var i = 0; i < 3; i++){
fs.push(makeFunc(i));
}
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
javascript using settimeout() with a loop
(4 answers)
Closed 9 years ago.
Simple question...
for (var i = 0; i < 5; i++) {
setTimeout(function () { alert(i) }, 3000);
}
how to alert 5 times with exact value of i.
It gives "5" only 5 times.
I need its result like
0
1
2
3
4
With a closure that keeps the value of the variable constant within the new scope of the immediately invoked function
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function () { alert(j) }, 3000);
}(i));
}
The setTimout is asynchronous, so by the time it executes the loop has long since completed, and the value of i has been changed to 5, so you need to lock it in.
You can use setInterval alternate to setTimeout
Try,
var xCnt = 0;
var xInterval = setInterval(function()
{
xCnt +=1;
alert(xCnt);
if(xCnt == 5)
{
clearInterval(xInterval);
}
}, 3000);
DEMO
This question already has answers here:
standalone parentheses in javascript [duplicate]
(5 answers)
Closed 8 years ago.
I am studying JavaScript and I sometimes see something like this
function functionname()
{
// Some statements
} () ;
What does () following } mean?
Thanks a lot, experts on Stack Overflow
That is an IIFE (immediately invoked function expression). It is used to create a new scope. For example:
var x = 10;
(function() {
var x = 5;
}());
alert(x); // still 10
All it does is define and call the function at the same time.
IIFEs are also used to "save" the value of a variable. For example, this code won't work:
for (var i = 0; i < buttons.length; i ++) {
buttons[i].onclick = function() { alert(i) }
}
Every button will alert the last index when you click it, because after the loop is done i is buttons.length. To fix it, you would use an IIFE:
for (var i = 0; i < buttons.length; i ++) {
buttons[i].onclick = (function(i) {
return function() {
alert(i)
}
})(i)
}
More info on IIFEs
It calls the function.
var foo = function () { return 1; }();
alert(foo); // 1
There are lots of ways to define a function, when you do it like this ...
(function functionname(innerArguments){
// Some statements;
})(outerArguments);
... the function is executed as soon as this piece of code is interpreted;
its the same as:
function functionname(innerArguments){
// Some statements;
};
functionname(outerArguments);