序文
ECMAScriptでは、関数オブジェクトを作成するために最も一般的に使用される2つの方法があります。つまり、関数式を使用するか、関数宣言を使用します。この点で、ECMAScriptの仕様により、関数宣言には常に識別子が含まれている必要があることが明らかになります。これは関数名と呼ばれるものであり、関数式は省略できます。 2つの違いの詳細な紹介を見てみましょう。
関数宣言とは何ですか?
関数宣言は、変数に値を割り当てることなく、名前付き関数変数を定義できます。関数宣言は、非機能モジュールにネストできない独立した構造です。可変宣言と比較できます。変数宣言が「var」で開始する必要があるように、関数宣言は「関数」から開始する必要があります。
例えば
function bar(){return 3;}ECMA 5(13.0)定義構文:
function Identifier ( FormalParameterList[opt] ) { FunctionBody }
関数名は、独自の範囲と親の範囲内で利用できます(それ以外の場合は、関数は使用できません)。
function bar(){return 3;} bar()// 3bar // function関数式とは何ですか?
関数式は、式ステートメントの一部として関数を定義します(通常は可変割り当て)。関数式で定義された関数は、名前または匿名です。関数式は「関数」で始まることはできません(以下のセルフコールの例は括弧内に囲む必要があります)。
例えば
//匿名関数expressionVar a = function(){return 3;} // niked function expressionvar a = function bar(){return 3;} // self invoking function expression(functionshello(){alert( "hello!");})();ECMA 5(13.0)定義構文:
function Identifieropt ( FormalParameterList[opt] ) { FunctionBody }
(この定義は条件を無視するため、不完全に感じます。周辺の声明は表現であり、「関数」から始まりません)
関数名(もしあれば)は、外部範囲(関数宣言と比較して)外部では利用できません。
では、関数ステートメントとは何ですか?
関数ステートメントは、機能宣言の別の方法です。しかし、Kangaxは、Mozillaでは、関数ステートメントは関数宣言の拡張であり、声明の使用を可能にする機能宣言ステートメントをどこでも使用できるようにすることを指摘しています。ただし、機能ステートメントは現在標準ではないため、製品開発に使用することはお勧めしません。
いくつかの小さなテストから始めましょう。次の状況で何がポップアップすると思いますか?
質問1:
function foo(){function bar(){return 3; } return bar(); function bar(){return 8; }} alert(foo());質問2:
function foo(){var bar = function(){return 3; }; return bar(); var bar = function(){return 8; };} alert(foo());質問3:
alert(foo()); function foo(){var bar = function(){return 3; }; return bar(); var bar = function(){return 8; };}質問4:
function foo(){return bar(); var bar = function(){return 3; }; var bar = function(){return 8; };} alert(foo());答えが8、3、3、[タイプエラー:barは関数ではない]でない場合は、読み続けます...(正しく答えても、読み続ける必要があります)
それでは、以前のテストについて説明しましょう。
質問1は関数宣言を使用しています。
待って、巻き上げは何ですか?
Ben Cherryからの引用は次のとおりです。「関数宣言と関数変数は、通常、JavaScriptインタープリターによって現在の範囲の上部に移動されます(「Hoisted」)。」
関数宣言が宣伝されると、それに応じて関数本体全体が促進されるため、質問1のコードは、通訳者によって説明された後にこのように実行されます。
// **質問1のシミュレートされた処理シーケンス** function foo(){// function bar(){return 3; } //関数bar(){return 8; } // Invocation Return bar()を返します。 // 8} alert(foo());ただし、returnステートメントの背後にあるコードが実行できないことがよくあります...
JavaScriptの実行中に、2つの概念があります。コンテキスト(ECMA 5は、それをlexicalenvironment、variaseenvironment、およびこのbindingに分解します)とプロセス(順番で呼ばれる一連のステートメント)。プログラムが実行ドメインに入ると、宣言は可変環境を引き起こします。それらはステートメント(返品など)とは異なり、ステートメント実行ルールに従わないでください。
関数式は促進されますか?
それは式に依存します。たとえば、質問2の最初の式:
var bar = function(){return 3;};等記号の左側にある(varバー)は可変宣言です。可変宣言は促進されますが、割り当て式は宣伝されません。したがって、バーが宣伝されると、通訳は次のように初期化されます:var bar =未定義。関数定義自体は宣伝されません。
(ECMA 5 12.2 initialzierを使用した変数は、変数が作成されたときではなく、Variablestatementが実行されるときにAssignmentExpressionによって割り当てられます。)
したがって、質問2のコードは次の順序で実行されます。
// **質問2のシミュレートされた処理シーケンス** function foo(){//各関数式の宣言var bar =未定義。 var bar =未定義; //最初の関数式が実行されますbar = function(){return 3; }; //最初の関数式によって作成された関数は、return bar(); // 2番目の関数式の到達不能} alert(foo()); // 3これは説明できると言うかもしれませんが、質問3への答えは間違っています。 FireBugを実行するときにエラーを報告します。
HTMLファイルにコードを保存し、Firefoxで実行してみてください。または、IE8、Chrome、またはSafariコンソールで実行します。明らかに、FireBugコンソールは、「グローバル」スコープでコードを実行するときに関数を宣伝しません(実際にはグローバルではなく、一意の「FireBug」スコープ - FireBugコンソールで「This ==ウィンドウ」を実行してみてください)。
質問3と質問1には同様のロジックがあります。今回はFOO機能が促進されました。
質問4は非常に単純で、機能の改善はまったくありません...
それは言えますが、まったく改善がなければ、TypeErrorは「機能ではなくバー」ではなく「定義されていない」になります。実際、この例では機能の改善はありませんが、変動の改善があります。したがって、バーは最初に宣言されますが、その値は定義されていません。他のコードは順番に実行されます。
// **質問4のシミュレートされた処理シーケンス** function foo(){//各関数式の宣言var bar = undefined; var bar =未定義; return bar(); // typeRerr: "bar not defined" //どちらの関数式にも達していない} alert(foo());他に何に注意を払うべきですか?
公式は、非機能モジュール(IFなど)での関数宣言の使用を禁止しています。ただし、すべてのブラウザはそれをサポートしていますが、それらの説明は異なります。
たとえば、次のコードスニペットは、関数宣言を関数ステートメントとして解釈するため(上記を参照)、xが定義されていないため、Firefox 3.6にエラーを投げかけます。ただし、IE8、Chrome 5、およびSafari 5では、関数Xが返されます(標準関数宣言と同じ)。
function foo(){if(false){function x(){}; } return x;} alert(foo());関数宣言を使用すると混乱を引き起こす可能性があることがわかります。そのため、利点はありますか?
関数宣言は非常にゆるいと言うかもしれません - 宣言の前に関数を使用しようとすると、プロモーションは実際に順序を修正して、関数を正しく呼び出すことができます。しかし、この種のゆるみは厳密なコーディングを助長するものではなく、長期的な観点からは、事故を防ぐのではなく促進する可能性があります。結局のところ、プログラマーが特定の順序でステートメントを配置する理由があります。
では、関数式をサポートする他の理由はありますか?
どう思いますか?
1)関数宣言は、Javaスタイルのメソッド宣言を模倣するように感じますが、JavaメソッドはJavaScriptと同じではありません。 JavaScriptでは、関数は値を持つ生きたオブジェクトです。 Javaメソッドは、メタデータのみの保管のみです。次の2つのコードが関数を定義しますが、オブジェクトが作成されているように見える関数式のみが表示されます。
// function declarationFunction add(a、b){return a + b}; // function expressionvar add = function(a、b){return a + b};2)関数式にはより多くの用途があります。関数宣言は、孤児には「ステートメント」としてのみ存在します。できることは、現在のスコープの下にオブジェクト変数を作成することだけです。定義上、関数式は大きな構造の一部です。匿名関数を作成したり、プロトタイプに関数を追加したり、他のオブジェクトのプロパティとして関数を使用したりする場合は、関数式を使用できます。 CurryやComposeなどの高度なアプリケーションを使用するときはいつでも、新しい関数を作成するときに関数式を使用します。関数表現と機能プログラミングは分離できません。
// function ExpressionVar sayshello = alert.curry( "hello!");
関数式に欠点はありますか?
関数式は、ほとんどの関数を匿名で作成します。たとえば、次の関数は匿名であり、今日は匿名関数への言及にすぎません。
var today = function(){return new date()}これには問題がありますか?ほとんどの場合ではありませんが、ニック・フィッツジェラルドが指摘したように、匿名の機能をデバッグするのは迷惑です。彼は、名前のある関数式(NFE)をワークスペースとして使用することをお勧めします。
var today = function today(){return new date()}ただし、Asen Bozhilovが言ったように(およびKangaxの文書)、NFEはIE9を正しく実行できません。
結論は
ランダムに配置された関数宣言は誤解を招くものであり、めったに(もしあれば)状況はめったにありません。関数式の変数に値を割り当てることは、関数宣言を置き換えることはできません。ただし、関数宣言が必要な場合は、スコープの一番上に置くと混乱を減らすことができます。 IFステートメントに関数宣言を入れないでください。
多くのことを言って、機能宣言はあなた自身の状況で役立つかもしれません。何でもありません。役割のドグマは危険であり、多くの場合、コードが茂みの周りで打ち負かされます。さらに重要なことは、概念を理解して、自分の状況に基づいて機能を作成する方法を決定できるようにすることです。上記は、この記事のコンテンツ全体です。この記事がこの点ですべての人に役立つことを願っています。