簡単に言えば...
どして
setTimeout('playNote('+currentaudio.id+', '+noteTime+')', delay);
完全に機能し、指定された遅延後に関数を呼び出しますが、
setTimeout(playNote(currentaudio.id,noteTime), delay);
関数playNoteをすべて同時に呼び出しますか?
(これらのsetTimeout()はforループ内にあります)
または、説明が読みにくい場合、2つの機能の違いは何ですか?
リストする最初のフォームは、delay
の最後の文字列を評価するため、機能します。 eval()
を使用することは一般に良い考えではないため、これを避ける必要があります。
関数呼び出し演算子_()
_で関数オブジェクトをすぐに実行するため、2番目の方法は機能しません。最終的には、playNote(...)
の形式を使用するとplayNote
がすぐに実行されるため、遅延の最後に何も起こりません。
代わりに、匿名関数をsetTimeoutに渡す必要があるため、正しい形式は次のとおりです。
_setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
_
関数式全体にsetTimeout
を渡すため、匿名関数を保持し、遅延の最後にのみ実行することに注意してください。
参照はすぐには実行されないため、setTimeout
参照を渡すこともできますが、引数を渡すことはできません。
_setTimeout(playNote, delay);
_
注:
繰り返しイベントの場合、setInterval()
を使用できます。また、setInterval()
を変数に設定して、変数を使用できます。 clearInterval()
で間隔を停止します。
for
ループでsetTimeout()
を使用すると言います。多くの場合、再帰関数でsetTimeout()
を使用することをお勧めします。これは、for
ループでは、setTimeout()
で使用される変数は、setTimeout()
が開始したときの変数ではなく、後の変数であるためです。関数が起動されるときの遅延。
この問題全体を回避するには、再帰関数を使用してください。
_ // Set original delay
var delay = 500;
// Call the function for the first time, to begin the recursion.
playNote(xxx, yyy);
// The recursive function
function playNote(theId, theTime)
{
// Do whatever has to be done
// ...
// Have the function call itself again after a delay, if necessary
// you can modify the arguments that you use here. As an
// example I add 20 to theTime each time. You can also modify
// the delay. I add 1/2 a second to the delay each time as an example.
// You can use a condition to continue or stop the recursion
delay += 500;
if (condition)
{ setTimeout(function() { playNote(theID, theTime + 20) }, delay); }
}
_
これを試して。
setTimeout(function() { playNote(currentaudio.id,noteTime) }, delay);
文字列タイムアウトを使用しないでください。有効なのはeval
で、これは悪いことです。 _currentaudio.id
_およびnoteTime
を自分自身の文字列表現に変換し、コード内に隠しているため、機能します。これは、それらの値が値を再作成するJavaScriptリテラル構文を生成するtoString()
sを持っている場合にのみ機能します。これはNumber
に当てはまります。
_setTimeout(playNote(currentaudio.id, noteTime), delay);
_
それは関数呼び出しです。 playNote
がすぐに呼び出され、関数の戻り値(おそらくundefined
)がsetTimeout()
に渡されます。
他の回答が言及しているように、クロージャーとともにインライン関数式を使用して、currentaudio
およびnoteTime
を参照できます。
_setTimeout(function() {
playNote(currentaudio.id, noteTime);
}, delay);
_
ただし、ループ内にあり、currentaudio
またはnoteTime
がループのたびに異なる場合は、クロージャーループの問題が発生します。すべてのタイムアウトで同じ変数が参照されるため、毎回同じ値、つまりループが以前に終了したときに変数に残された値を取得すると呼ばれます。
anotherクロージャーでこれを回避し、ループの各反復に対して変数の値のコピーを取得できます。
_setTimeout(function() {
return function(currentaudio, noteTime) {
playNote(currentaudio.id, noteTime);
};
}(currentaudio, noteTime), delay);
_
しかし、これは少しbitいものになっています。より良いのは_Function#bind
_で、これは関数を部分的に適用します:
_setTimeout(playNote.bind(window, currentaudio.id, noteTime), delay);
_
(window
はthis
の値を関数内に設定するためのもので、これはbind()
の機能であり、ここでは必要ありません。)
ただし、これはECMAScript第5版の機能であり、すべてのブラウザーがまだサポートしているわけではありません。したがって、それを使用する場合は、最初にサポートでハッキングする必要があります。
_// 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)));
};
}
};
}
_
2番目のものはplayNote関数firstを呼び出してから、戻り値をsetTimeoutに渡すように指示しているためです。
Javascriptがコードを実行するタイミングと、何かの実行を待機するタイミングを理解するのに役立つ場合があります。
let foo2 = function foo(bar=baz()){ console.log(bar); return bar()}
=>
_構文の関数キーワード構文を使用すると、同様の( ただし同一ではない )結果が得られます。foo2
_に割り当てられますbaz
もbar
も、値も参照されていません。しかし、関数内で構文がチェックされています。foo
または_foo2
_をsetTimeout
に渡すと、タイムアウト後に、foo()
と同じように関数が呼び出されます。 (引数がfoo
に渡されないことに注意してください。これは、setTimeout
がデフォルトで引数を渡さないためです 可能ですが ですが、それらの引数はタイムアウトになるのではなく、タイムアウトになる)bar
のデフォルトが評価されます。 (引数を渡した場合、これは起こりませんでした)bar
のデフォルト引数を評価する際、最初のjavascriptはbaz
という名前の変数を探します。見つかった場合は、関数として呼び出します。それが機能する場合、戻り値をbar
に保存します。bar
を検索し、結果とともにconsole.logを呼び出します。これはbarを呼び出しません。ただし、代わりにbar()
として呼び出された場合、bar
が最初に実行され、その後bar()
の戻り値が_console.log
_に渡されます。 javascriptは、呼び出している関数の引数の値を取得していることに注意してくださいbefore関数を呼び出し、関数をルックアップする前でもそれは存在し、実際に機能です。bar
を再度検索し、関数として呼び出します。それが機能する場合、値はfoo()
の結果として返されますしたがって、関数本体とデフォルトの引数はすぐには呼び出されませんが、他のすべては呼び出されます。同様に、関数呼び出し(つまり_()
_)を実行すると、その関数もすぐに実行されます。ただし、関数を呼び出す必要はありません。括弧を省略すると、その関数を渡し、後で呼び出すことができます。ただし、その欠点は、関数の呼び出しに使用する引数を指定できないことです。また、javascriptは関数の括弧before内ですべてを実行し、関数を呼び出すか、関数が保存されている変数を検索します。