Don't use string-timeouts. It's effective an eval
, which is a Bad Thing. It works because it's converting currentaudio.id
and noteTime
to the string representations of themselves and hiding it in the code. This only works as long as those values have toString()
s that generate JavaScript literal syntax that will recreate the value, which is true for Number
but not for much else.
setTimeout(playNote(currentaudio.id, noteTime), delay);
that's a function call. playNote
is called immediately and the returned result of the function (probably undefined
) is passed to setTimeout()
, not what you want.
As other answers mention, you can use an inline function expression with a closure to reference currentaudio
and noteTime
:
setTimeout(function() {
playNote(currentaudio.id, noteTime);
}, delay);
However, if you're in a loop and currentaudio
or noteTime
is different each time around the loop, you've got the Closure Loop Problem: the same variable will be referenced in every timeout, so when they're called you'll get the same value each time, the value that was left in the variable when the loop finished earlier.
You can work around this with another closure, taking a copy of the variable's value for each iteration of the loop:
setTimeout(function() {
return function(currentaudio, noteTime) {
playNote(currentaudio.id, noteTime);
};
}(currentaudio, noteTime), delay);
but this is getting a bit ugly now. Better is Function#bind
, which will partially-apply a function for you:
setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
(window
is for setting the value of this
inside the function, which is a feature of bind()
you don't need here.)
However this is an ECMAScript Fifth Edition feature which not all browsers support yet. So if you want to use it you have to first hack in support, eg.:
// Make ECMA262-5 Function#bind work on older browsers
//
if (!('bind' in Function.prototype)) {
Function.prototype.bind= function(owner) {
var that= this;
if (arguments.length<=1) {
return function() {
return that.apply(owner, arguments);
};
} else {
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner, arguments.length===0? args : args.concat(Array.prototype.slice.call(arguments)));
};
}
};
}
ctr-k
to do this. – Gora