ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptを深く理解するシリーズ(4) すぐに呼び出せる関数式_javascriptスキル

JavaScriptを深く理解するシリーズ(4) すぐに呼び出せる関数式_javascriptスキル

WBOY
WBOYオリジナル
2016-05-16 17:57:08927ブラウズ

はじめに
JavaScript を学習すると、匿名関数を自己実行するコードによく遭遇します。今日は主に自己実行について説明します。
これについて詳しく知る前に、この記事でのこの機能の名前は完全に正しいとは限らないため、人によってはこれをどう理解するかによって異なります。はすぐに呼び出されるので、自分の理解に応じて名前を選択することができます。ただし、多くの人がそれを「自己実行」と呼ぶと聞きましたが、著者は後に「」と呼ぶように説得するためにこう言いました。即時呼び出し「.関数式」。
この記事の英語のオリジナルアドレス: http://benalman.com/news/2010/11/immediately-invoked-function-expression/
自己実行とは何ですか?
JavaScript では、関数に対して宣言された変数と関数は関数内にのみ存在するため、関数は実行時に実行コンテキストを作成します。このコンテキストは、関数を呼び出すときに自由変数を作成する簡単な方法を提供します。またはプライベートサブ関数。

コードをコピー コードは次のとおりです:

// この関数は別の関数を返すため、その中で、この関数は自由変数 i
// にアクセスできます。つまり、この内部関数は実際には内部オブジェクトを呼び出す権限を持っています。
function makeCounter() {
// makeCounter 内でのみアクセスできます
var i = 0;
return function () {
console.log( i); ;
}
// counter と counter2 は異なるインスタンスであり、それぞれ独自の範囲に i があることに注意してください。
var counter = makeCounter();
counter(); // ログ: 1
counter(); // ログ: 2
var counter2 = makeCounter(); ; // ログ: 1
counter2(); // ログ: 2
alert(i); // 参照エラー: i が定義されていません (i が makeCounter 内に存在するため)。


多くの場合、makeCounter の複数のインスタンスは必要ありません。場合によっては、戻り値を表示する必要もありません。

問題の核心
function foo(){} や var foo = function(){} のような関数を宣言するとき、最後に括弧を追加することで自己実行を実現できます。 foo( ) として、コードを確認します:


コードをコピーします コードは次のとおりです:
// 以下の最初の関数が必要なので、宣言された関数は、foo()、
// のように、その後に括弧 () を追加することで単独で実行できます。foo は式 function( への単なる参照であるため) ) { /* code */ }
var foo = function(){ /* code */ }
// ...最後に括弧を付けても自動的に実行できるということですか? ?
function(){ /* code */ }(); // SyntaxError: Unexpected token (
//


上記のコードは、実行してもエラーになります。パーサーがグローバル関数または関数内部関数キーワードを解析するとき、コンパイラーに明示的に指示しない場合、デフォルトで関数式ではなく関数宣言が使用され、名前のない関数がスローされるためです。関数宣言には名前が必要なため、構文エラー メッセージが表示されます。
余談: function、かっこ、syntaxError (SyntaxError)
興味深いことに、前の名前でも構文エラーが表示されますが、理由は異なります。上記では、式の後に括弧 () を追加すると、式はすぐに実行されますが、ステートメントの後に括弧 () を追加すると、意味がまったく異なり、単なるグループ化演算子

コードをコピー
コードは次のとおりです。 >// 次の関数は文法的には正しいですが、まだ単なるステートメントです // 括弧 ( )、グループ化演算子には式 function foo(){ /* code */ }(); // SyntaxError: Unexpected token ) // を含める必要があるため、引き続きエラーが報告されます。括弧 () で式を渡すと、例外はスローされません // ただし、foo 関数 function foo(){ /* code */ }( 1 );
// はまだ実行されません。これは、関数宣言の後に、無関係な関数が宣言されているコードと完全に等価です。
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
    名前付き関数式
  1. - Juriy “kangax” Zaytsev モジュールモードの総合分析
  2. - Ben Cherry (翻訳・編集:おじさん) JavaScript で説明されたクロージャ
  3. - Nick Morgan
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。