Function name expected on closure - javascript

I have the following code:
for(var i = 0; i <=3; i++){
setTimeout(function(){
var j = i;
function(){
console.log(j);
}
}, 1000);
}
I am getting an error 'Function name expected' on the second function. I don't understand why I can't use an anonymous function here.

To create a closure and call it right away do this:
(function(){
console.log(j);
}());
But, to actually capture the i correctly for the inner function, you can move the function up a bit and pass it i:
for (var i = 0; i <= 3; i++) {
(function(i){
setTimeout(function(){
console.log(i);
}, 1000);}(i));
}
And, to actually print the numbers 1 second after each other, you can do this:
for (var i = 0; i <= 3; i++) {
(function(i){
setTimeout(function(){
console.log(i);
}, 1000*(i+1));}(i));
}

Based on Jordão's answer, I ended up using the following code:
for(var i = 0; i <=3; i++){
(function(){
var j = i;
setTimeout(function(){
console.log(j);
}, 1000);
}());
}

So you know for the future you can get your output with a smaller (and cleaner?) number of lines of code if you use recursion:
function loop(i) {
console.log(i = i || 0);
if (i <= 3) setTimeout(loop, 1000, ++i);
}
loop();
DEMO

Related

JavaScript setTimeout not workig as expected

I have a code sample
for(var i = 0; i < 3; i++) {
setTimeout() {
console.log("i " + i)
}
}
This is printing "3" to the console three times. However, I want it to print "0, 1, 2" without using let.
So far, I have tried the following -
var funcs = [];
function createfunc(i) {
return function() {
console.log("i ", i)
}
}
for(var i = 0; i < 3; i++) {
setTimeout(() => {
funcs[i] = createfunc(i) // statement 1
}, 1000)
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
This is working fine if I use the statement 1 just as it is without putting it into the setTimeout function. However, it is throwing an error if I'm using the setTimeout function. Can someone let me know how can I make print 0, 1, 2 to the console using the setTimeout function ?
It happens because of closure, anyway you can use the below codes, then you will be getting the proper result that you want.
for(var i = 0; i < 3; i++) {
((i) => {
setTimeout(() => {
console.log("i " + i)
}, 0);
})(i);
}

immediately-invoked function calling setTimeout calling for loop

In the following scenario, event setTimeout get queued and only after stack clears out, i = 3 will print 3 times
//ver1
for (var i = 0; i < 3; i ++ ) setTimeout(()=> console.log(i), 3)
The following will print 1 2 3 in order since i is captured in func x ??
//ver2
for (var i = 0; i < 3; i++) {
(function x(i) {
setTimeout(() => {console.log(i)}, 30)
})(i);
}
Why the following only prints 2 one time?
//ver3
for (var i = 0; i < 3; i++) {
function x(i) {
setTimeout(() => {console.log(i)}, 30)
}(i);
}
I'm mostly confused between ver2 and ver3
EDIT:
ver2 explanation can be found here. Any insight on why ver3 only prints 2?
Your version 3 doesn't do at all what you think it does. Parenthesis are not optional on an IIFE. But because you named the function, it does get parsed as a function declaration:
for (var i = 0; i < 3; i++) {
function x(i) {
setTimeout(() => {console.log(i)}, 30)
}
(i);
}
You were never calling x(…) here. The (i) is just an unnecessarily-parenthesised expression evaluating the i variable. Your code executes the same as
for (var i = 0; i < 3; i++) {
i;
}
So why does this log 2 in the console? Because when you run this on the console, it prints the result value of the statement that was evaluated last: i, which had the value 2 in the last iteration of the loop.

The reason of the output in setTimeout

Here is the code
function fn(){
for (var i = 0; i < 4; i++) {
var tc=setTimeout(function(i){
console.log(i)
clearTimeout(tc)
},10,i);
}
}
fn()
//0, 1, 2 - output
I can't understand why the output is not '0, 1, 2, 3',only output three times.
Even more stranger is below
When I change the loop times, now, I call loop times as T.
T: 1 ---> 0
T: 2 ---> 0
T: 3 ---> 0, 1
above, the right is the output.
Here you go. Print i out at interval T.
function fn(){
var T = 1000;
var func = function(i,len) {
if ( i < len ) {
console.log(i);
setTimeout(func,T,i+1,len); // Calling itself.
}
};
setTimeout(func,T,0,4);
}
fn();
At last got it...The problem is with closure..You just need to pass the variable tc to setTimeout function.
function fn(){
for (var i = 0; i < 4; i++) {
var tc=setTimeout(function(i,tc){
console.log(i)
clearTimeout(tc);
},10,i,tc);
}
}
fn()
What you are doing is that you are overwriting the value of tc in the for loop.
By overwriting, you lose handle to corresponding return value from each call to setTimeout().
You need to clear individual tc as you go in the for loop.
So, something like this would work.
Note that I have hard-coded, tc array but you can make it generic, so this example is just for a reference as to how you could get 0,1,2,3.
var tc = [0,0,0,0];
function fn(){
for (var i = 0; i < 4; i++) {
tc[i]=setTimeout(function(i){
console.log(i);
clearTimeout(tc[i]);
},10,i);
}
}
fn();

Stop passing by reference in closures [duplicate]

This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I have code that looks like this:
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
}
}
Unfortunately, it seems that i is being passed by reference, so all the functions in a output 10. How do I make it so that each function outputs the value that i had when it was created? I.e. a[0]() gives 0, a[1]() gives 1, etc.
EDIT: to clarify, I do not want a to store the values 0-9. I want a to store functions that return the values 0-9.
You need to invoke a function (to create a closure that captures your value) which returns a function (the one you want to end up with). Something like this:
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = (function(value) {
return function() {
console.log(value);
}
})(i);
}
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = (function(j) {
return function () {
console.log(j);
}
})(i);
}
A better performing version -
function makeFunction(i) {
return function () {
console.log(i);
}
}
var a = [];
for(var i = 0; i < 10; i++) {
a[i] = makeFunction(i);
}
JSFiddle Demo.

passing number to function for loop with jquery

I was wondering how to pass a number to a function I created for a loop. For example, I have a loop that simply adds 1 to a value when it runs. How would I go about passing how many times I want the loop to run in a function? Like so:
var i = 0;
function blahBlah (i ?){
for (i=0,i>10(this is what I want to pass to the function),i++){
i++;
}
Then call the function:
blahBlah(number of times I want it to run);
I'm not sure i understand the question, but how about
function blahBlah(n) {
for(var i=0; i < n; i++) {
//do something
}
}
function blahBlah (noOfTimes){
for (var i=0 ;i < noOfTimes ;i++){
//i++; you already incremented i in for loop
console.log(i);//alert(i);
}
}
blahBlah(10);// call function with a loop that will iterate 10 times
You mean calling the function each iteration?
function blahBlah( i ) {
// do something with i
}
for ( var i = 0; i < 10; i++ ) {
blahBlah( i );
}
Maybe like this:
function runLoop(length) {
for (var i=0; i < length; i++) {
{loop actions}
}
}
First, you used , instead of ; in for loop.
Second, you need two variables here: the first one is how many times to repeat (i, the argument), the second is a counter (a, which iteration is it now)
function blah(i) {
for (var a=0; a<i; a++) {
doStuff();
}
}
Use a loop inside your function:
function BlahBlah(n) {
for (i=0; i < n; ++i) {
// do something...
}
}
or simply invoke the function in a for loop:
function Blahblah() { /* do something */ }
// elsewhere:
n = 42;
for (i=0; i < n; ++i) BlahBlah();

Categories

Resources