I want to pass an argument to a function called using setTimeout
. I have found these three options:
A = 1;
// Method 1: closure things
setTimeout(function() { whatsA(A); }, 100);
// Method 2: third argument (same result with [A])
setTimeout(whatsA, 100, A);
// Method 3: eval
setTimeout('whatsA(' + A + ')', 100);
A = 2;
function whatsA(X) { console.log(X); }
This shows 2
, undefined
, and 1
in Internet Explorer 9.
Method 1: Clearly, I would not like the argument to be changed after passing it (certainly in the case of simple integers).
Method 2: This would be perfect if only Internet Explorer supported it.
Method 3: This seems to be the only choice. But it seems rather less pretty than the others, passing something to be evaluated rather than a function.
Is there a better way?
The best solution I can think of is using bind()
:
A = 1;
setTimeout(whatsA.bind(this, A), 100);
Because bind()
is actually a function invocation, it reads the current A
value and returns a function with that value bound as an argument. If you find it hard to understand, try this:
var newFun = whatsA.bind(this, 42);
newFun()
Note that this
is kind of a lie here - you can safely pass window
as well.
The first method is also acceptable, it just needs to be slightly improved:
A = 1;
var tmpA = A;
setTimeout(function() { whatsA(tmpA); }, 100);
What you are observing is actually a feature, not a bug. You are passing a closure to setTimeout()
referencing local variable. JavaScript is clever enough to delay access to that variable up to the moment when the function is actually called. And since you have modified the variable, you see the most recent version.
The second method is deprecated won't work in any browser.
Third method is terrible, avoid passing string to setTimeout()
, there is always a better solution.
You could use closure:
setTimeout((function(A){
return function(){
whatsA(A);
};
})(A), 100);
Of your three methods:
Option 1:
setTimeout(function() { whatsA(A); }, 100);
This one works everywhere and is simple. It's what I would recommend unless the variable A
might change before the setTimeout function is called. If you need to freeze the value of A
, then see my option 4 below.
Option 2:
setTimeout(whatsA, 100, A);
This only works in some browsers. Not recommended.
Option 3:
setTimeout('whatsA(' + A + ')', 100);
This is never recommended. Constructing code as a string and then evaluating it later is almost never the best solution.
I would recommend Option 4:
To freeze the value of A
, you can create a closure using a self executing function:
A = 1;
function(A) {
setTimeout(function() {whatsA(A);}, 100);
}(A);
A = 2;
function whatsA(X) { console.log(X); }