For loop is not iterating within setTimeout [duplicate] - javascript

This question already has answers here:
How do JavaScript closures work?
(86 answers)
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 3 years ago.
I'm trying to figure out why this for loop does not render out 0,1,2,3 like its suppose to.
It renders 4, 4 , 4, 4.
How would i get this to print 0, 1, 2, 3 with the setTimeout still in place ?
for (var i = 0; i < 4; i++) {
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 3000);
}

Create another and call it on each iteration
function a(i)
{
setTimeout(function() {
console.log('The index of this number is: ' + i);
}, 3000);
}
for (var i = 0; i < 4; i++) {
a(i);
}

Related

Function calls with loops [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
Why when I click on my buttons there are always 100 in console log? And how I can fix this?
function SampleFunction(param){
console.log(param);
}
for (i = 0; i < 100; i++) {
$("#btn-" + i).on('click',function(e){
SampleFunction(i);
});
}
use let keyword
for (let i = 1; i < 9; i++) {
$("#btn-" + i).on('click',function(e){
SampleFunction(i);
});
}
Pure js approach
let allButtons = document.getElementsByTagName('button');
for(i=0;i<allButtons.length;i++) {
allButtons[i].onclick = getPosition;
}
function getPosition() {
let position = Array.from(allButtons).indexOf(this) + 1;
console.log(`you clicked button at position ${position}`)
}
<button id="button-1">1</button>
<button id="button-2">2</button>
<button id="button-3">3</button>
<button id="button-4">4</button>

How to push a declared function into an array and later invoke it [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
The following code works great. It pushes 10 unnamed functions into an array and then successfully executes the 7th item in the array.
var storeStuff = [];
for (let i = 0; i < 10; i++) {
storeStuff.push(function() {
console.log(i * i);
});
}
storeStuff[6]();
However the test function above is tiny. If I had a large function with many lines of code I'd likely want to declare it outside of the push.
For example what if I wanted to push a previously defined function and later invoke it like the example below?
var storeStuff = [];
function externalFunction(temp) {
console.log(temp * temp)
}
for (let i = 0; i < 10; i++) {
storeStuff.push(externalFunction(i));
}
storeStuff[6]();
Unfortunately this doesn't work as written and everything I've tried crashed and burned. What am I getting wrong?
Use function declaration as below
var storeStuff = [];
externalFunction = function(temp) {
console.log(temp * temp)
}
for (let i = 0; i < 10; i++) {
storeStuff.push(externalFunction);
}
storeStuff[6](6);

dealing with loops in javascript, only last item gets affected? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
Im working with the gm npm module that deals with image manipulation. and i have this code.
for(i=0;i < 4;i++){
gm("www/img/" + image[i]).crop(550, 406, 0, 0).write(function(err) {
console.log(this.outname + " created :: " + arguments[3]); //success
});
}
this loop is meant to loop through the images array and crop each photo, but it only crops the last one. i think its something to do function invocation and callbacks, but not advanced yet for that level.
Change your code to:
for (var i = 0; i < 4; i++) {
(function (i) {
gm("www/img/" + image[i]).crop(550, 406, 0, 0).write(function(err) {
console.log(this.outname + " created :: " + arguments[3]); //success
});
}).call(this, i);
}
otherwise the value of i will be 3 each time your callback is being invoked.
You need to create a "closure" over the variable
Js has a function scope.
for (i = 0; i < 4; i++)
{
(function (a)
{
gm("www/img/" + image[a]).crop(550, 406, 0, 0).write(function (err)
{
console.log(this.outname + " created :: " + arguments[3]); //success
});
}).call(this,i)
}
or
that=this;
for (i = 0; i < 4; i++)
{
(function (a)
{
gm("www/img/" + image[a]).crop(550, 406, 0, 0).write(function (err)
{
console.log(that.outname + " created :: " + arguments[3]); //success
});
})(i)
}
edit :
Also - I would also keep a reference to the arguments since now , after IIFE - the arguments is changing.
you can keep your arguments via :
var args= Array.prototype.slice.apply(arguments)
example :
function g()
{
for (i = 0; i < 4; i++)
{
(function (a)
{
console.log(arguments); //huh ? arguments are not a,b,c !!! anymore
})(i);
}
}
g('a','b','c') // 0,1,2,3
so you do need to keep reference to the arguments cuz their changed after IIFE.

jQuery and setTimeout inside For loop [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
setTimeout in for-loop does not print consecutive values [duplicate]
(10 answers)
Closed 8 years ago.
I just encountered a very weird issue (I fixed it though) but I wanted to know why did it happen in the first place:
function stuffAppear() {
var i;
for (i = 0; i < speech.length; i++) {
apperance(i);
}
}
function apperance(i) {
var x = speech[i];
setTimeout(function() {$(speech[i]).fadeIn(1000); console.log(i);}, 1000 + i * 1500);
console.log(speech[i]);
}
The console log shows "#yo0" then "#ma0b" (which is the required) but at the same time, they never faded in
I played around with the code until I reached this:
function stuffAppear() {
var i;
for (i = 0; i < speech.length; i++) {
apperance(i);
}
}
function apperance(i) {
var x = speech[i];
setTimeout(function() {$(x).fadeIn(1000); console.log(i);}, 1000 + i * 1500);
}
And that did the trick, but I don't know why the first code didn't work. Can someone explain that to me, please?
And thank you!
In a JSFiddle both versions work fine (and the same):
First: http://jsfiddle.net/TrueBlueAussie/Bkz55/3/
var speech = ["#yo0", "#ma0b", "#blah"];
function stuffAppear() {
var i;
for (i = 0; i < speech.length; i++) {
apperance(i);
}
}
function apperance(i) {
var x = speech[i];
setTimeout(function() {$(speech[i]).fadeIn(1000); console.log(i);}, 1000 + i * 1500);
console.log(speech[i]); // <<< THIS WOULD OCCUR IMMEDIATELY
}
Second: http://jsfiddle.net/TrueBlueAussie/Bkz55/4/
var speech = ["#yo0", "#ma0b", "#blah"];
function stuffAppear() {
var i;
for (i = 0; i < speech.length; i++) {
apperance(i);
}
}
function apperance(i) {
var x = speech[i];
setTimeout(function() {$(x).fadeIn(1000); console.log(i);}, 1000 + i * 1500);
}
So I suspect what you are seeing is a side effect of your other code (not shown).
The only odd thing is you were logging in the first version twice (once outside the setTimeout which would display at the start - as you mentioned)
Follow up:
Having now seen the real code, the cause was changing of the speech array during the timeouts. When the timeout function was finally hit the speech array was empty!

Javascript: using global variable in the function definition [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 9 years ago.
I am trying to execute the following code:
for (var i = 0; i <= 9; ++i) {
State.prototype["button" + i.toString()] = function () {
console.log("I am a digit button" + i.toString());
this.setValue(i.toString());
};
}
But it is wrong, because the i variable is common for all the function created.
For example I want the function State.prototype.button0() to work as:
console.log("I am a digit button" + "0");
this.setValue("0");
How to do it?
Pass it to a function, so that the value of i doesn't change:
for (var i = 0; i <= 9; ++i) {
(function(i){
State.prototype["button" + i.toString()] = function () {
console.log("I am a digit button" + i.toString());
this.setValue(i.toString());
};
})(i);
}

Categories