名前付き関数式を使用する理由


92

JavaScriptで関数式を実行するには、2つの異なる方法があります。

名前付き関数式(NFE)

var boo = function boo () {
  alert(1);
};

無名関数式

var boo = function () {
  alert(1);
};

そして、どちらもで呼び出すことができますboo();。なぜ/いつ匿名関数を使用する必要があるのか​​、いつ名前付き関数式を使用するべきなのか、本当にわかりません。それらの間にはどのような違いがありますか?


回答:


85

無名関数式の場合、関数は匿名です  —文字通り、名前はありません。割り当てる変数には名前がありますが、関数にはありません。(更新:ES5でそれは真実でした。ES2015[別名ES6]以降、匿名式で作成された関数は、真の名前を取得しますが、自動識別子ではありません)。

名前は便利です。名前は、スタックトレース、コールスタック、ブレークポイントのリストなどで確認できます。名前はGood Thing™です。

彼らは誤って[私のブログの記事により2つの完全に異なる時間に2つの完全に独立した関数オブジェクトを作成したので、(あなたは、[以下IE8と] IEの古いバージョンで指定された関数式に注意する必要があるために使用されるダブルテイク ]。あなたが必要な場合IE8 [!!]をサポートします。無名の関数式または関数宣言を使用することをお勧めしますが、名前付き関数式は使用しないでください。)

名前付き関数式の重要な点の1つは、関数の本体内に関数のその名前を持つスコープ内識別子を作成することです。

var x = function example() {
    console.log(typeof example); // "function"
};
x();
console.log(typeof example);     // "undefined"

ただし、ES2015の時点では、多くの「匿名の」関数式が名前付きの関数を作成します。これは、コンテキストから名前を推測することについて非常に賢いさまざまな最新のJavaScriptエンジンによって先行されていました。ES2015では、無名関数式の結果はという名前の関数になりますboo。ただし、ES2015 +のセマンティクスを使用しても、自動識別子は作成されません。

var obj = {
    x: function() {
       console.log(typeof x);   // "undefined"
       console.log(obj.x.name); // "x"
    },
    y: function y() {
       console.log(typeof y);   // "function"
       console.log(obj.y.name); // "y"
    }
};
obj.x();
obj.y();

関数名の割り当ては、仕様のさまざまな操作で使用されるSetFunctionName抽象操作で行われます。

短いバージョンは、基本的に、次のように、割り当てや初期化などの右側に匿名関数式が表示される場合です。

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

(またはそれであるかもしれないletまたはそれconstよりむしろvar))、または

var obj = {
    boo: function() { /*...*/ }
};

または

doSomething({
    boo: function() { /*...*/ }
});

(最後の2つは実際には同じものです)、結果の関数には名前(boo例では)が付けられます。

重要かつ意図的な例外があります。既存のオブジェクトのプロパティに割り当てるには:

obj.boo = function() { /*...*/ }; // <== Does not get a name

これは、新機能が追加される過程で情報漏えいの懸念が生じたためです。詳細はこちらの別の質問に対する私の回答


1
NFEを使用しても具体的な利点が得られる場所が少なくとも2つあることに注意する必要があります。まず、new演算子を介してコンストラクターとして使用することを目的とした関数の場合(そのようなすべての関数名を指定すると、.constructorプロパティがデバッグ中に、何が問題なのかを理解するのに役立ちます)一部のオブジェクトは)のインスタンスであり、関数リテラルの場合、最初にプロパティまたは変数に割り当てられることなく関数に直接渡されます(例:)setTimeout(function () {/*do stuff*/});。Chromeでさえ(anonymous function)、名前を付けて手助けしない限り、これらを表示します。
Mark Amery 2015

4
@MarkAmery:「これは本当ですか?私は...これらのルールでCTRL-Fを試してみましたが、見つかりませんでした」 ああそうです。:-)一連のルールを定義する1つの場所ではなく、仕様全体に散らばっています。「setFunctionName」を検索してください。上記のリンクの小さなサブセットを追加しましたが、現在は29か所まで表示されます。もしあなたのsetTimeout例がのためsetTimeoutに宣言された仮引数から名前を取得しなかったとしても、それがあったとしても、少し驚いただけです。:-)しかし、はい、NFEは、それらのハッシュを作成する古いブラウザを処理しないことがわかっている場合に、間違いなく役立ちます。
TJクラウダー2015

24

名前付け関数は、自分自身を参照する必要がある場合に便利です(たとえば、再帰呼び出しの場合)。実際、リテラル関数式を引数として別の関数に直接渡す場合、その関数式は、名前が指定されていない限り、ES5 strictモードでそれ自体を直接参照することはできません

たとえば、次のコードを考えてみます。

setTimeout(function sayMoo() {
    alert('MOO');
    setTimeout(sayMoo, 1000);
}, 1000);

渡された関数式setTimeoutが匿名の場合、このコードをこれほどきれいに書くことは不可能です。代わりに、setTimeout呼び出しの前にそれを変数に割り当てる必要があります。このように、名前付き関数式を使用すると、少し短くてすっきりします。

これまでは、無名関数式を使用してこのようなコードを作成することが可能でしたarguments.callee...

setTimeout(function () {
    alert('MOO');
    setTimeout(arguments.callee, 1000);
}, 1000);

...しかしarguments.callee非推奨であり、ES5 strictモードでは完全に禁止されています。したがって、MDNは次のように助言します。

関数式に名前を付けるか、関数がそれ自体を呼び出さなければならないところで関数宣言を使用することarguments.callee()によって、使用を避けます。

(強調鉱山)


3

関数が関数式として指定されている場合、名前を付けることができます。

関数内でのみ使用できます(IE8-を除く)。

var f = function sayHi(name) {
  alert( sayHi ); // Inside the function you can see the function code
};

alert( sayHi ); // (Error: undefined variable 'sayHi')

この名前は、別の変数に書き込まれた場合でも、信頼できる再帰的な関数呼び出しを目的としています。

さらに、NFE(名前付き関数式)の名前はObject.defineProperty(...)、次のメソッドで上書きできます。

var test = function sayHi(name) {
  Object.defineProperty(test, 'name', { value: 'foo', configurable: true });
  alert( test.name ); // foo
};

test();

注:関数宣言では、これは実行できません。この「特別な」内部関数名は、関数式構文でのみ指定されます。


2

常に名前付き関数式を使用する必要があります。それが理由です。

  1. 再帰が必要な場合は、その関数の名前を使用できます。

  2. 問題の原因となる関数の名前がわからないため、デバッグ時に匿名関数は役に立ちません。

  3. 関数に名前を付けないと、後でその関数の機能を理解するのが難しくなります。名前を付けると、わかりやすくなります。

var foo = function bar() {
    //some code...
};

foo();
bar(); // Error!

ここでは、たとえば、名前バーは関数式内で使用されているため、外部スコープでは宣言されません。名前付き関数式では、関数式の名前はそれ自体のスコープ内に含まれます。


1

のような非推奨の機能に依存する必要なく、問題の関数を参照できるようにしたい場合は、名前付き関数式を使用する方が適切ですarguments.callee


3
それは答えというよりはむしろコメントです。おそらく詳細な説明が有益でしょう
vsync 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.