7

次のコードが、括弧が含まれている場合にスタックオーバーフローが発生する理由について頭を悩ませようとしていますが、括弧が含まれている場合はそうではありません。

関数自体をsetTimeoutの引数として呼び出しており、括弧なしで機能しますが、もちろん、関数を追加すると失敗します。関数の後に()を追加するのは私の直感でした。誰かが私のためにこれを片付けることができることを願っています。パランはいつオプションであり、そうではありませんか?

ケース1:

var a = 1;

function foo() {
    a++;
    document.write(a);
    setTimeout(foo(), 2000)
}​ 
// RangeError: Maximum call stack size exceeded

ケース2:

var a = 1;

function foo() {
    a++;
    document.write(a);
    setTimeout(foo, 2000)
}​
// parens are omitted on foo function and it works. 
4

2 に答える 2

12

この質問は通常、を参照して最初に尋ねられますがsetTimeout、ここでの動作はその機能に固有のものではないことを指摘することが重要だと思います。かっこが何をするのか、そしてかっこを省略した場合の意味を理解する必要があります。

次の関数を想定します。

function foo() {
    return 5;
}

次の2つの変数宣言/割り当てを検討してください。

var one = foo();
var two = foo;

これらの変数にはどのような値がありますか?

最初のケースでは、関数を実行fooし、その戻り値(数値)をに割り当ててい5ますonefoo2番目のケースでは、それ自体(より正確には、への参照)をにfoo割り当てていますtwo。関数が実行されることはありません。

この知識と、setTimeout最初の引数として関数への参照を期待する理解があれば、最初のケースが失敗する理由は明らかですが、2番目のケースは機能します。

もちろん、実行している関数がそれ自体への再帰呼び出しであるという事実によって、問題は悪化します。再帰を終了する基本ケースがないため、これは永久に実行されます(永久の定義では)。

于 2012-07-09T21:37:35.287 に答える
9

書くことによって

foo()

その時点で実際にfooを呼び出しています。もちろん、これはfoo()を再度呼び出します...stackoverflowまで。

ケース2では、「これを2秒で実行する」と言って、効果的に「参照」をfooに渡します。実際にはfoo()を呼び出していません。

したがって、実際に呼び出したい場合は、parensを使用してください。あなたがそれを参照したいときではありません。

于 2012-07-09T21:23:43.087 に答える