再帰ではない
再帰のように見えるかもしれませんが、setTimeout は再帰を作成しません。
setTimeout が機能する方法は、すぐに戻ることです。したがって、への呼び出しはk
、そのスタックの割り当てが解除された状態ですぐに終了します。
タイムアウトが実際に発生し、への呼び出しgo
が再度発生した場合、それは前の呼び出しのポイントからではなくk
、グローバル スコープからのものです*。
* 注: ここでは、ECMAScript 仕様で定義されているスコープの厳密な意味を使用していません。私が言いたいのは、 への呼び出しk
は、プレーンなタグで書いたかのように行われるということです<script></script>
。つまり、他の関数呼び出しの外側です。
閉店の懸念について
あなたの特定のケースでは、関数によって作成されたクロージャーに実際に囲まれているものはほとんどありませんk
。唯一の重要なクロージャーは、引数cb
およびへの参照myId
です。それでも、約 1 秒間しか持続しません。
#1 function k(myId, cb) {
#2 setTimeout(function(){
#3 console.log(myId); // there is a closure here to myId
#4 cb(); // and another one for cb
#5
/* But at this point in the function, setTimeout ends
* and as the function returns, there are no remaining
* references to either "cb" or "myId" accessible
* anywhere else. Which means that the GC can immediately
* free them (though in reality the GC may run a bit later)
*/
#6 }, 1000); // So one second is roughly the longest the closure lasts
}
もっと簡単かもしれません
あなたのコードはかなり複雑であることに注意してください。次のように単純に書くと、クロージャーをまったく使用せずに(グローバル変数 i を差し引いて)、より簡単に書くことができます。
// Simpler, does exactly the same thing:
var i = 0;
function go () {
console.log(i);
i++;
setTimeout(go, 1000); // callback
}
go();