function foo(){} や var foo = function(){} のような関数を宣言するとき、最後に括弧を追加することで自己実行を実現できます。 foo( ) として、コードを確認します:
// のように、その後に括弧 () を追加することで単独で実行できます。foo は式 function( への単なる参照であるため) ) { /* code */ }
var foo = function(){ /* code */ }
// ...最後に括弧を付けても自動的に実行できるということですか? ?
function(){ /* code */ }(); // SyntaxError: Unexpected token (
//
上記のコードは、実行してもエラーになります。パーサーがグローバル関数または関数内部関数キーワードを解析するとき、コンパイラーに明示的に指示しない場合、デフォルトで関数式ではなく関数宣言が使用され、名前のない関数がスローされるためです。関数宣言には名前が必要なため、構文エラー メッセージが表示されます。
興味深いことに、前の名前でも構文エラーが表示されますが、理由は異なります。上記では、式の後に括弧 () を追加すると、式はすぐに実行されますが、ステートメントの後に括弧 () を追加すると、意味がまったく異なり、単なるグループ化演算子
function foo(){ /* code */ }
( 1 );
詳細については、ECMA-262-3 の第 5 章「関数」を参照してください。
自己実行関数式
上記の問題を解決するには、JavaScript では文を括弧 () で囲むことができないため、非常に簡単です。 point function キーワードを解析するとき、パーサーは対応するコードを関数宣言ではなく関数式に解析します。
// 次の 2 つの括弧 () はすぐに実行されます
(function () { /* code */ } ()) // これを使用することをお勧めします
(function () { /* code */ })();これも使用できます
// 括弧 () と JS の &&、XOR、カンマ、およびその他の演算子は関数式と関数宣言を明確にするため
// したがって、パーサーがそれらの 1 つがすでに式であることを認識すると、その他はデフォルトですべて式です
// ただし、次の章の内容の説明に注意してください
var i = function () { return 10; } ();
true && function (); /* code */ } ();
0, function () { /* code */ } ()
// 戻り値を気にしない場合、または難しいことを恐れない場合
// を読み取るには、単項演算記号
を追加することもできます!function () { /* code */ } ();
~function () { /* code */ } () ;
-function () { /* code */ } ();
function () { /* code */ } (); new キーワードを使用する場合もあります。も使用できますが、よくわかりません 効率
// http://twitter.com/kuvos/status/18209252090847232
new function () { /* code */ }
new function () { /* code */ } () // パラメーターを渡す必要がある場合は、括弧を追加するだけです ()
上記の括弧は、実際には曖昧さを避けるためのものです。括弧は本来関数式であることが想定されているため、まったく必要ありませんが、主に開発者が読みやすくするために、これらの自動的に実行される式を変数に割り当てるときに括弧 (() が表示されます。
クロージャを使用して状態を保存する
通常の関数を実行するときにパラメータを渡すのと同じように、自己実行します。これらのパラメータを渡されると、自己実行関数式はこれらのロックされた受信パラメータを使用して状態を効果的に保存できるため、関数式はこの方法でパラメータを渡すこともできます。
// 変数が次のとおりであるため、このコードは間違っています。私は決してロックされていません
// 逆に、ループが実行された後は、クリックしたときにのみ値を取得します
// この時点で実際に値を取得するため
// したがって、問題はありませんどの接続がクリックされたか、最後に表示されるのは、リンク #10 です (a 要素が 10 個ある場合)
var elems = document.getElementsByTagName('a');
for (var i = 0; i <) ; elems.length; i ) {
elems[i].addEventListener('click', function (e) {
e.preventDefault();
alert('I am link #' i);
}, 'false');
}
// これは自己実行関数式クロージャ内にあるため使用できます
// i の値はロックされたインデックスとして存在し、ループ内で実行される 終了後、最終的に i の値は a 内の要素の総数 (例えば 10) になりますが
// クロージャ内の lockedIndex の値は実行されているため変化しません
// したがって、接続時間をクリックすると、正しい結果が得られます。
var elems = document.getElementsByTagName('a');
for (var i = 0; i
(function (lockedIndex) {
elems[i].addEventListener('click', function (e) {
e.preventDefault();
alert('私はリンク #' lockedInIndex);
}, 'false' );
})(i);
}
// ハンドラー関数
の自己実行関数式を使用して、次のように適用することもできます。 // 外側の addEventListener の代わりに
// しかし、比較的に言うと、上記のコードの方が読みやすいです
var elems = document.getElementsByTagName('a');
for (var i = 0; i < elems .length; i ) {
elems[i].addEventListener('click', (function (lockedIndex) {
return function (e) {
e.preventDefault();
alert('私はリンク #' lockedIndex);
})(i), 'false');
実際、上記の 2 つの例の lockedIndex 変数は i に置き換えることもできます。これは外部 i と同じ関数では動作しないため、これも匿名関数クロージャの能力です。 。
自己実行匿名関数と即時実行関数式の違い
この投稿では、これを常に自己実行関数と呼んでいます。正確には、自己実行匿名関数 (Self -匿名関数の実行) ですが、元の英語のテキストでは、著者は常に即時呼び出し関数式という名前の使用を推奨してきました。著者は、説明するためにたくさんの例も示しました。
// これは自己実行関数であり、関数自体が実行されます。内部的に、再帰的に
function foo() { foo(); }
// マークされた名前がないため、これは自己実行型の匿名関数です
// 実行するには、arguments.callee 属性を使用する必要があります
var foo = function () { argument.callee() };
// これは、foo タグ名だけがそれ自体を参照する場合もあります。 foo を別の関数に変更すると、慣れ親しんだ自己実行型の匿名関数が得られます。
var foo = function () { foo() }; これを自己実行型の匿名関数と呼ぶ人もいます。 (そうでなくても)自分自身を呼び出さないので、すぐに実行するだけです。
(function () { /* code */ } ());
// 関数式にラベル名を追加するとデバッグが容易になります
// ただし、ラベル名を付ける必要があり、関数は匿名です
(function foo() { /* code */ } ());
// 即時に呼び出される関数式 (IIFE) も自己実行できますが、一般的には使用されない可能性があります。 🎜> (function () { argument.callee(); } ());
(function foo() { foo(); } ());
// さらに、次のコードが実行されます。 BlackBerry 5 エラー、名前付き関数式で名前が定義されていないため
// はは、奇妙です
(function foo() { foo(); } ());
ここでのいくつかの例が、誰もが自己実行とは何か、即時召命とは何かを理解するのに役立つことを願っています。
注: argument.callee は ECMAScript 5 厳密モードでは廃止されているため、このモードでは使用できません。
最後のナレーション: モジュール モード
このすぐに呼び出される関数式について話しているときに、このモードに慣れていない場合は、最初にコードを見てみましょう。
// 公開したい内容を含む変数を返します // 返された変数は、外部で宣言された関数自体ではなく、カウンターに割り当てられます
var counter = (function () {
var i = 0;
return {
get: function () {
return i;
},
set: function (val) {
i = val ; >},
increment: function () {
return i;
}
} ()); カウンターは複数のオブジェクトです上記のコードは実際にはメソッド
counter.set(3); // 4
counter として反映します。 .increment(); // 5
counter.i; // i は返されたオブジェクトのプロパティではないため未定義です
i; // 参照エラー: i が定義されていません (i はクロージャ内にのみ存在するため)
モジュール パターンの詳細については、前回の投稿「JavaScript を深く理解するシリーズ (2): モジュール パターンの包括的な分析」を参照してください。
続きを読む
さらに詳しく知りたい場合は、上記の例のいくつかを参照して、すぐに呼び出される関数 (つまり、自己実行関数と呼ばれるもの) の式を理解していただければ幸いです。関数とモジュール パターン 詳細については、引き続き以下の Web サイトにアクセスしてください:
ECMA-262-3 の詳細第 5 章。機能
- ドミトリー A. ソシニコフ
関数と関数スコープ
- Mozilla Developer Network
名前付き関数式- - Juriy “kangax” Zaytsev
モジュールモードの総合分析
- - Ben Cherry (翻訳・編集:おじさん)
JavaScript で説明されたクロージャ
- - Nick Morgan