それは何ですか
JavaScriptでは、各関数が呼び出されると、新しい実行コンテキストが作成されます。関数で定義されている変数と関数は、関数を呼び出すときに外部ではなく内部でアクセスされる唯一の変数であるため、関数によって提供されるコンテキストは、プライベート変数を作成する非常に簡単な方法を提供します。
function makecounter(){var i = 0; return function(){console.log(++ i); }; } //覚えておいてください: `counter`と` counter2`には独自の変数があります `i`var counter = makecounter(); counter(); // 1counter(); // 2var counter2 = makecounter();多くの場合、複数の蓄積された値を返すためにmakewhateverのような関数は必要ない場合があり、単一の値を取得するために1回だけ呼び出すことができます。他の場合には、戻り値を明示的に知る必要さえありません。
そのコア
これで、関数foo(){}またはvar foo = function(){}などの関数を定義しても、foo()のように、その後の括弧を追加する必要があります。
//以下に定義する関数は、 `foo()`、//のように関数名の後にブラケットのペアを追加することで呼び出すことができます。その後? function(){ / * code * /}(); // syntaxerror:予期しないトークン(ご覧のとおり、ここでバグが捉えられます。関数を呼び出すために関数の背後に表示されると、グローバル環境またはローカル環境でそのような関数キーワードに遭遇するかどうかにかかわらず、デフォルトでは、関数式ではなく関数宣言として扱います。括弧で式であることを明示的に伝えない場合、関数宣言には名前が必要であるため、名前のない関数として扱い、エラーを投げます。
質問1:ここで質問を考えてもいいですか?また、このように直接furnce var foo = function(){console.log(1)}()を呼び出すこともできます。答えは問題ありません。
質問2:同様に、質問についても考えることができます。このような関数宣言が括弧で直接呼び出された場合、何が起こりますか?以下の答えをご覧ください。
関数、括弧、エラー
興味深いことに、関数の名前を指定し、その背後に括弧を並べると、同じエラーがスローされますが、今回は別の理由です。括弧が関数式の後に配置されると、これは関数と呼ばれる関数であり、括弧が宣言の後に配置されることを示します。これは、以前の関数宣言から完全に分離されていることを意味します。この時点で、括弧は括弧の単純な表現です(操作の優先順位を制御するために使用されるブレース)。
//ただし、関数宣言は構文的に無効であり、まだ宣言であり、次の括弧は無効です。なぜなら、括弧には式機能foo(){/* code*/}(); // syntaxerror:syntaxerror:syntaxerror:syntaxerror:undeective expensed token // */}(1)//それは次のものと同等です。関数宣言は、関係のない式に続きます:function foo(){/ *code */}(1);機能式をすぐに実行する(iife)
幸いなことに、文法エラーを簡単に修正するのは簡単です。最も人気があり、最も受け入れられている方法は、括弧内に関数宣言をラップして、パーサーに関数式を表現するように指示することです。これは、javaScriptでは、括弧内に宣言を含めることができないためです。このため、括弧が関数をラップするために関数キーワードに遭遇すると、関数宣言の代わりに関数式として解析することがわかります。ここでの括弧は、関数に遭遇したときに上記の括弧とは異なることを理解することに注意してください。
匿名関数の最後に括弧が表示され、関数を呼び出すと、関数を関数宣言として扱うようにデフォルトが表示されます。
括弧内に関数をラッピングすると、関数を宣言するのではなく、デフォルトで式として関数を解析します。
//両方のパターンを使用して、関数の実行を使用してプライベート変数を作成するために機能式をすぐに呼び出すことができます(function(){/ * code */}()); // crockfordはこれを推奨します。オペレーターは、関数式と関数宣言の間で//を非表示にすることです。パーサーが既に式を期待している場合(ただし、以下の//「重要なメモ」を参照してください)。vari = function(){return 10;}(); true && function(){/*code*/}();可能なことに、あなたはあなたの関数の前に単一のオペレーターを取ることでバイトを保存できます! function(){/ * code */}(); 〜function(){/ * code */}(); - function(){/ * code */}();+function(){/ * code */}(); // @kuvosからの別のバリエーション - パフォーマンスはわかりません// http://twitter.com/kuvos/status/18209252090847232New function(){/ * code */} new function(){/ * code */}()//ブラケットに関する重要なメモ
場合によっては、追加のあいまいなブラケットが関数式の周りにある場合(ブラケットはすでに式として表現されているため)、関数式を囲む必要はありませんが、ブラケットが関数式を呼び出すために使用される場合はまだ良い考えです。
このような括弧は、関数式がすぐに呼び出され、変数が関数自体ではなく関数の結果を保存することを示しています。これが非常に長い関数式である場合、これにより、ページの下部にスクロールして関数が呼び出されているかどうかを確認することなく、コードを読んでいる人よりも時間を節約できます。
原則として、明確で明確なコードを書くとき、JavaScriptがエラーを投げかけるのを防ぐ必要があります。また、他の開発者がwtferrorにエラーを投げかけるのを防ぐ必要もあります。
閉鎖のステータスを保存します
名前で関数が呼び出されたときと同じように、パラメーターは渡され、関数式がすぐに呼び出されると、パラメーターが渡されます。関数内で定義されている関数は、外部関数によって渡されるパラメーターと変数を使用できるため、直ちに値と呼ばれる関数式を使用して状態を効果的に保存できます(この関係は閉鎖と呼ばれます)。
//「I」の値がロックされていないため、あなたが思うように機能しないかもしれません。 //逆に、各リンクがクリックされると(ループが適切に実行されています)、したがって、すべての要素の総数がポップアップします。これは、この時点で「I」の真の値であるためです。 var elems = document.getElementsBytagname( 'a'); `I`値は `lockedinindex`にロックされています。 //ループが実行されると、「I」値の数値はすべての要素の合計ですが、関数式が呼び出されるたびに、iifeの「lockedinindex」値は「i」によって渡される値です。 var elems = document.getElementsByTagname( 'a'); })(i);} //次のようにiifeを使用することもできます。括弧を使用してクリック処理関数を含めて、「addeventlistener」全体を含めません。 //どちらの方法でも、両方の例をiifeでロックできますが、前の例はより読みやすいvar elems = document.getelementsbytagname( 'a'); for(var i = 0; i <elems.length; i ++){elems [i] .addeventlistener( 'click){e.denindex){e.dedex){e.dedex) alert( 'a relink#' + lockedinindex); }これらの最後の2つの例では、LockedInindexは問題なくIにアクセスできることを忘れないでください。
関数をすぐに実行することの最も重要な利点の1つは、たとえ名前が付けられていないか匿名でなくても、識別子を使用せずに関数式をすぐに呼び出すことができ、現在の変数を汚染することなく閉鎖を使用できることです。
匿名関数を自己実行することの問題は何ですか(「「自己実行匿名関数」)?
あなたはそれが何度か言及されているのを見たことがありますが、それはまだそれほど明確に説明されていません、私はあなたが略語が好きなら、「すぐにvokedされた関数式」、またはiifeにこの用語を変更することを提案することをお勧めします。
すぐにvokedされた関数式とは何ですか?すぐに呼ばれる関数式を作成します。それはあなたが呼び出すように導く関数式のようなものです。
JavaScriptコミュニティのメンバーは、概念を理解しやすく、「自己実行匿名関数」という用語は実際には十分ではないため、記事や声明で、即座にvokedされた関数表現、Iifeの用語、即席の関数表現、Iifeを受け入れることができるはずです。
//以下は自己実行機能であり、これは独自の関数foo(){foo();}; //これは自己実行匿名関数です。識別子がないため、 `arguments.callee`プロパティを使用してそれ自体と呼ぶ必要がありますvar foo = function(){arguments.callee();}; //匿名の関数は、たとえそれがそれ自体と呼ばれないために自己実行していなくても、このようなものです。その後、すぐに呼ばれました。 (function(){/*code*/}()); //識別子を関数式に追加する(つまり、指定された関数を作成する)ことは、デバッグに大きな助けになります。名前が付けられたら、関数は匿名ではなくなります。 (function foo(){/ * code */}()); // iifeは単独で実行できますが、おそらく最も有用なパターンではありません(function(){arguments.callee();}())素晴らしい、huh?(function foo(){foo();}());上記の例が、機能が実行されているにもかかわらず、独自の機能を実行していないため、やや誤解を招く自己執行という用語をより明確に理解できるようになることを願っています。同様に、匿名関数を指摘する必要はありません。これは、すぐに呼び出された関数式が指定された関数または匿名関数のいずれかになる可能性があるためです。
最後:モジュールモード
関数式を呼び出すと、モジュールパターンについて少なくとも一度は思い出させると、それを無視する可能性が高いでしょう。 JavaScriptにモジュールパターンがない場合は、以下の私の例に非常に似ていますが、戻り値は関数の代わりにオブジェクトを使用します。
var counter =(function(){var i = 0; return {get:function(){return i;}、set:function(val){i = val;}、increment:function(){return ++ i;}}}}()); counter.get(); // 0 counter.set(3); counter.increment();/4 counter.increment(); // 5 conuter.i; // undefined( `i`は返されたオブジェクトのプロパティではありません)i;モジュールモードメソッドは非常に強力であるだけでなく、単純です。コードが非常に少ないと、メソッドと属性に関連するネーミングを効果的に利用できます。オブジェクトでは、すべてのモジュールコードを整理すると、グローバル変数の汚染が最小化され、変数の使用が作成されます。