2

私が始めた別のスレッドへのコメントで、誰かがこれを言いました:

@adlwalrusはい。これを試してください:var foo = function bar(){}; console.log(foo); ただし、barは関数名(正確には自分自身がわからないという意味)であり、それへの参照ではないため、bar()を実行して呼び出すことはできないことに注意してください。また、(名前付き関数であっても)割り当てることは、関数を宣言することと同じではありません。巻き上げ(スコープの一番上にぶつかる)は宣言に対してのみ機能し、割り当てはそのまま残ります。–valentinas6時間前

関数名を呼び出すことができない場合、関数名はどのような目的に役立ちますbar()か?

4

3 に答える 3

4

関数がそれ自体を呼び出すため。

var x = function y(val){
            if (val){
                console.log(val);
                y(val-1);
            }
        }; 
x(5);
> 3  
> 2  
> 1 
y(3); 
> ReferenceError: y is not defined
于 2012-09-06T03:26:54.103 に答える
4

名前付き関数式を参照しています。仕様では、そのような関数の名前は、新しい関数のスコープ内でのみ使用可能である必要があります。スペック見積もり

FunctionExpressionの識別子は、FunctionExpressionのFunctionBody内から参照して、関数がそれ自体を再帰的に呼び出すことができるようにすることができます。ただし、FunctionDeclarationとは異なり、FunctionExpressionの識別子は、FunctionExpressionを囲むスコープから参照することはできず、影響を与えることもありません。

一方、その式の結果は、新しい関数への参照であり、どこにでも保存および参照できます。

ここに多くの詳細:

私は全部を読みました。

利点として、もう1つは、デバッガーでの識別が容易になることです。

于 2012-09-06T03:33:33.907 に答える
3

JavaScriptで関数を作成するには、「関数宣言」と「関数式」の2つの方法があります。「関数」が特定の行の最初の文字セットでない限り、関数式(宣言ではない)を実行していると彼が指摘したときに最もよく説明したのはダグ・クロックフォードだったと思います。

関数宣言は気難しい生き物です。あなたがそれらを見るとき、あなたはそれらを認識するでしょう。彼らはこのように見えます:

function foo() { /* ... */ }

それらには常に名前が付けられ(必要です)、その名前は、関数が宣言されている字句コンテキストにローカルでスコープされます。したがって、グローバルコンテキストで関数宣言を実行すると、その名前を介して関数をグローバルに参照できます。関数内で行う場合、関数の名前は、その関数内およびその関数内で宣言された関数内でのみ参照できます。

関数を宣言するこの方法(ほとんどコメントされないもの)の最も重要な側面は、関数の初期化が現在の字句コンテキストの先頭に引き上げられることだと思います。したがって、次のような条件内で関数宣言を使用しないでください。

//DON'T DO THIS!
if (x) {
    function foo() { return 1; }
} else {
    function foo() { return 2; }
}

foo(); //will always be 2, regardless of the value of x.

関数式は少し異なります。多くの場合、次のように、変数に直接割り当てられます。

var foo = function() { /* ... */ };

これは、初期化が引き上げられないことを除いて、上記の関数宣言とほぼ同じです。したがって、次のことができます。

var foo;
if (x) {
    foo = function() { return 1; };
} else {
    foo = function() { return 2; };
}

foo(); //will be 1 or 2, depending on the truthy-ness of x. 

では、元の質問に戻りましょう。関数式にも名前を付けることができますが、名前は必須ではなく、関数が宣言されているコンテキストにスコープされていません(関数宣言の場合と同様)。代わりに、関数自体の字句コンテキストにスコープが設定されます。これは場合によっては非常に便利です。私の個人的なお気に入りはこのパターンです:

(function foo() {
    //Do something.

    setTimeout(foo, 1000);
}());

foo; //undefined

「関数」という単語の前に括弧があるため、これは関数式であり、名前は内部でのみスコープされます。しかし、それは問題ありません。内部的に(を介してsetTimeout())呼び出すだけでよいからです。その結果、関数はすぐに1回実行され、実行が終了した後、1秒ごとに再実行されます。setInterval()これは、実行が完了するまで待機してから再スケジュールするため、使用するよりも安全です。これにより、実行の失敗やJavaScriptスレッドの「支配」を引き起こす可能性のある重複が防止されます。

基本的に、名前付き関数式の使用は制限されていますが、必要な場合は非常に強力です。

于 2012-09-06T04:23:13.287 に答える