ホームページ > 記事 > ウェブフロントエンド > JavaScript_javascript スキルにおける関数宣言と関数式の違いの簡単な分析
私がテンセントでインターンとして面接していたとき、面接官が私にこの質問をしたのを覚えています。
最初は関数宣言と関数式という 2 つの宣言方法しか知らなかったので、具体的な違いを説明できませんでした。最近たまたまこのテーマに関する本を見つけたので、それについてまとめてみようと思いました。
ECMAScript では、関数オブジェクトを作成するために最も一般的に使用される 2 つの方法があります。それは、関数式を使用する方法と関数宣言を使用する方法です。この点に関して、ECMAScript 仕様では、関数宣言には常に関数名と呼ばれる識別子 (Identifier) が必要であり、関数式は省略できることが明確にされています。
関数宣言:
1. Functionオブジェクトを新規作成し、FormalParameterListでパラメータを指定し、FunctionBodyで関数本体を指定します。現在実行中の環境内のスコープ チェーンをスコープとして使用します。
2. 現在の変数オブジェクトの Identifier という名前の属性を、値 Result(1) で作成します。
関数式:
(関数式は匿名関数式と名前付き関数式に分かれます)
名前付き関数式の解析プロセスは次のとおりです:
1. 新しいオブジェクトを作成します
2. Result(1) をスコープ チェーンの先頭に追加します
3. 新しい Function オブジェクトを作成し、FormalParameterList にパラメータを指定し、FunctionBody に関数本体を指定します。現在実行中の実行環境のスコープ チェーンをスコープとして使用します。
4. Result(1) の Identifier という名前の属性を作成します。その値は Result(3) で、読み取り専用で、削除できません
5. スコープチェーンから Result(1)
を削除します。
6. 結果を返す(3)
公式ドキュメントは非常に読みにくいです。簡単に言えば、ECMAScript はコンテキストを通じて 2 つを区別します。関数 foo(){} が代入式の一部である場合、それは関数式とみなされます。また、関数 foo(){} が関数本体内に含まれているか、プログラム (の最上位) に配置されている場合、関数宣言として解析されます。明らかに、識別子が省略された場合、「式」は式のみになります。
別の状況もあります:
このケースも関数式であり、そのコンテキストでは、() はグループ化演算子を構成し、グループ化演算子には式のみを含めることができます。
関数宣言と関数式の類似点と相違点について簡単に説明しましょう。宣言と式の動作には、微妙ですが重要な違いがあります。
まず、式が解析されて評価される前に、 関数宣言が解析されて評価されます 。宣言がソース コードの最後の行であっても、同じスコープ内の最初の式より前に評価されます。例を見ると理解しやすいです。次の例では、alert の後に関数 fn が宣言されています。ただし、アラートが実行されるとき、fn はすでに定義されています:
簡単にまとめると、何が違うのでしょうか?
関数宣言にはもう 1 つの重要な特徴があります。
。つまり:
FunctionDeclaration は、Program または FunctionBody 内でのみ使用できます。構文的には、ブロック ({ ... }) 内 (たとえば、if、while、または for ステートメント内) にこれらを使用することはできません。 Block には Statement のみを含めることができ、FunctionDeclaration などの SourceElement は含めることができないためです。
一方、生成ルールを詳しく見てみると、式をブロック内に出現させる唯一の方法は、それを ExpressionStatement の一部にすることであることがわかります。ただし、仕様では、ExpressionStatement をキーワード関数で開始できないと明確に述べられています。これが実際に意味するのは、FunctionExpression を Statement または Block 内に使用できないということです (Block は Statement で構成されているということを忘れないでください)。
上記の制限により、関数がブロック内に出現するときは常に (上の例のように)、関数の宣言や式ではなく、実際には構文エラーとして扱われる必要があります。
では、関数宣言や関数式はどのようなときに使用すればよいのでしょうか?関数宣言は「プログラム コード」内でのみ出現できます。つまり、関数宣言は、他の関数本体またはグローバル空間内でのみ出現できます。その定義は、変数や属性に割り当てたり、関数呼び出しのパラメーターとして渡すことはできません。例としては、関数宣言の使用が許可されており、foo()、bar()、および local() はすべて関数宣言モードで宣言されています:
私の知識には限界があるので、間違いがあれば修正してください。