Не используйте строковые таймауты.Это эффективный eval
, что плохо.Это работает, потому что он конвертирует currentaudio.id
и noteTime
в строковые представления себя и скрывает это в коде.Это работает только до тех пор, пока эти значения имеют toString()
s, которые генерируют синтаксис литерала JavaScript, который воссоздает значение, что верно для Number
, но не для многих других.
setTimeout(playNote(currentaudio.id, noteTime), delay);
, это вызов функции,playNote
вызывается немедленно, и возвращенный результат функции (вероятно, undefined
) передается setTimeout()
, а не тому, что вы хотите.
Как уже упоминалось в других ответах, вы можете использовать встроенное выражение функции сзамыкание на ссылку currentaudio
и noteTime
:
setTimeout(function() {
playNote(currentaudio.id, noteTime);
}, delay);
Однако, если вы находитесь в цикле, а currentaudio
или noteTime
каждый раз отличается от цикла, вы получаетепроблема замкнутого цикла: в каждый тайм-аут будет ссылаться одна и та же переменная, поэтому при их вызове вы будете получать одно и то же значение каждый раз, то значение, которое оставалось в переменной, когда цикл завершался ранее.
Вы можете обойти это с другим закрытием, беря копию значения переменной для каждой итерации цикла:
setTimeout(function() {
return function(currentaudio, noteTime) {
playNote(currentaudio.id, noteTime);
};
}(currentaudio, noteTime), delay);
, но теперь это становится немного уродливым.Лучше будет Function#bind
, что частично применимо для вас:
setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
(window
- для установки значения this
внутри функции, которая является функцией bind()
Вам здесь не нужно.)
Однако это функция пятого издания ECMAScript, которую поддерживают не все браузеры.Так что, если вы хотите использовать его, вы должны сначала взломать поддержку, например ::
// 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)));
};
}
};
}