javascriptを詳しく説明すると、すぐに関数式(IIIFE)を実行します.

17141 ワード

前に書く
これは訳文で、原文:Immedial tely-Invoked Function Expression(IIIIIIIIIIIIIIIIIFSE) 
原文は非常に古典的な解説IIIIFEの文章で、コレクションに適しています.この文章は訳文ですが、直訳は少ないです.自分の理解も多く追加しました.
ps:下記の「即時実行関数」は、「即時実行関数式」です.
私たちが言いたいのは何ですか?
javascriptでは、各関数は呼び出された時に一つの実行コンテキストを作成します.この関数の内部で定義された変数と関数はこの関数の内部でしか使用できません.このコンテキストのため、関数を呼び出した時にいくつかのプライベート変数を作成することができます.
// makeCounter            ,    makeCounter      i     

function makeCounter() {

  // i  makeCounter        

  var i = 0;



  return function() {

    console.log( ++i );

  };

}



//   counter counter2      ,            i  



var counter = makeCounter();

counter(); // 1

counter(); // 2



var counter2 = makeCounter();

counter2(); // 1

counter2(); // 2



i; //   ,i    ,   makeCounter       
多くの場合、上記のコードのように多くのインスタンスを初期化する必要はありません.
  • 問題の核心
  • 今は関数(function foo(){}またはvar foo=function(){}を定義しています.関数名に小さな括弧を加えると、下記のコードのような関数の呼び出しが完了します.
    var foo = function(){ /* code */ };
    
    foo();
    次のコードを見に行きます.
    function(){ /* code */ }(); // SyntaxError: Unexpected token (
    新聞を間違えました.これはなぜですか?これは、Javascriptコードの解釈において、Fnctionキーワードに出会うと、関数宣言ではなく関数宣言としてデフォルトになります.関数式ではなく、関数式として明示的に表現されていない場合は、関数名が必要です.上のコードには関数名がありません.(以上のコードは、最初の左括弧(時報が間違っています.(前の理論は関数名があるべきです.)
  • 一波がまた起きました.
    面白いことに、私たちが関数名をあげたら、すぐに呼び出しても同じです.今回のエラーの原因は違っています.
    function foo(){ /* code */ }(); // SyntaxError: Unexpected token )
    なぜこのようになったのですか?1つの表式の後に括弧を付けて、この表式がすぐに実行されることを表します.一方、文の後に括弧を入れると、括弧は完全に前の文と一致しません.1つのグループのオペレータだけで、演算の優先度(小括弧内の先演算)を制御します.
    function foo(){ /* code */ }
    
    (); // SyntaxError: Unexpected token )
    まずfooという関数を宣言してから()内の表式演算を行いますが、()内の表式は空ではないので、エラーが発生します.
    もっと知りたいなら、ECMA-622-3 in detail.Chapter 5.Functions.を参照してください.
    すぐに関数を実行します.
    ここを見たら、きっと待っていると思います.一体どうしたらいいのか分かりたいです.実は簡単です.括弧で全部まとめてもいいです.たとえば、以下のように.
    (function(){ /* code */ }());
    なぜこのようにすぐに実行できますか?Javascriptでは、括弧内に語句が含まれていないため、解析器がコードを解釈すると、まず()にぶつかり、その後、functionキーワードに出会うと自動的に関数式ではなく関数式として認識されます.
    すぐに実行する関数は上記のような書き方だけではないです.書き方は本当に多種多様です.
    //         
    
    (function(){ /* code */ }()); //       
    
    (function(){ /* code */ })(); //        
    
    
    
    //    JS      (  = && || , )                  
    
    //      ,              ,              
    
    //           
    
    var i = function(){ return 10; }();
    
    true && function(){ /* code */ }();
    
    0, function(){ /* code */ }();
    
    
    
    //
    
    !function(){ /* code */ }();
    
    ~function(){ /* code */ }();
    
    -function(){ /* code */ }();
    
    +function(){ /* code */ }();
    
    
    
    //       
    
    new function(){ /* code */ }
    
    new function(){ /* code */ }() //    
  • いつでも、即時実行関数に括弧をつけるのはいい習慣です.
    以上の紹介を通して,()関数式をすぐに実行できることを大体理解した.
    ある時、私達は実際に関数式を使う必要がありません.どういう意味ですか?たとえば、この行のコードは、()を付けなくても大丈夫です.
    var i = function(){ return 10; }();
    しかし、私たちは相変わらずお勧めします.
    var i = (function(){ return 10; }());
    なぜですか?コードを読んでいる間に、フュージョン内部のコード量が膨大であれば、最後までスクロールしてフュージョン(){}を確認しなければなりません.i値はフュージョンかフュージョンかを判断します.コードの読み取り可能性のためには、表式であるかどうかは関係なく、できるだけ()を加えてください.
  • 直ちに関数とクローズド曖昧関係を実行します.
    即時実行関数は、クローズドの保存状態に合わせて使用できます.
    普通の関数がパラメータを転送するように、すぐに関数を実行してもパラメータを転送できます.関数の内部にもう一つの関数を定義すれば、その関数は外部の変数とパラメータ(クローズド)を参照できます.この点を利用して、すぐに関数を実行して変数の保存状態をロックすることができます.
    //             ,  i       
    
    //           ,  for        
    
    //         i       elems.length 
    
    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     lockedIndex,        
    
    //   for     i      ,          lockedIndex       
    
    var elems = document.getElementsByTagName( 'a' );
    
    
    
    for ( var i = 0; i < elems.length; i++ ) {
    
    
    
      (function( lockedInIndex ){
    
    
    
        elems[ i ].addEventListener( 'click', function(e){
    
          e.preventDefault();
    
          alert( 'I am link #' + lockedInIndex );
    
        }, 'false' );
    
    
    
      })( i );
    
    
    
    }
    
    
    
    
    
    //
    
    var elems = document.getElementsByTagName( 'a' );
    
    
    
    for ( var i = 0; i < elems.length; i++ ) {
    
    
    
      elems[ i ].addEventListener( 'click', (function( lockedInIndex ){
    
        return function(e){
    
          e.preventDefault();
    
          alert( 'I am link #' + lockedInIndex );
    
        };
    
      })( i ), 'false' );
    
    
    
    }
    実は上のコードのlockedIndexもiに変えられます.二つのiは異なる作用領域にあるので、お互いに邪魔しないです.でも、違う名前を書いたらもっといいです.以上はすぐに関数+クローズドの役割を果たします.
  • 私はなぜ「自己実行関数」ではなく「即時実行関数」と呼びたいですか?
    IIFの呼称は現在では広く普及されているようですが、原文は10年に書かれています.当時流行していたような呼称は自己執行関数(Self-executing anonymous function)です.続いて著者は、すぐに実行する関数の呼び方が実行関数よりもいいと説明するために、理論に基づいて論争を始めました.
    //          ,          ,    
    
    function foo() { foo(); }
    
    
    
    //
    
    //                 arguments.callee
    
    var foo = function() { arguments.callee(); };
    
    
    
    //               ,    foo       
    
    //     foo      ,      used-to-self-execute    
    
    var foo = function() { foo(); };
    
    
    
    //             ,         ,        
    
    (function(){ /* code */ }());
    
    
    
    //              ,    debug
    
    //
    
    (function foo(){ /* code */ }());
    
    
    
    //
    
    (function(){ arguments.callee(); }());
    
    (function foo(){ foo(); }());
    著者は、自己実行関数は関数内部で自分を呼び出すものと考えていますが、すぐに実行する関数は文字通り実行すればいいです.実は今はそれを管理しなくてもいいです.IIIFEといいます.
  • 最後のナレーション:モジュールモード
  • 即時実行関数はモジュール化においても大きな役割を果たします.すぐに関数処理モジュール化を実行することで、グローバル変数による空間汚染を低減し、より多くのプライベート変数を構築することができます.
    //              
    
    //
    
    //                ,       i
    
    //       i,      counter.i  i  
    
    //                  
    
    
    
    var counter = (function(){
    
      var i = 0;
    
    
    
      return {
    
        get: function(){
    
          return i;
    
        },
    
        set: function( val ){
    
          i = val;
    
        },
    
        increment: function() {
    
          return ++i;
    
        }
    
      };
    
    }());
    
    
    
    // counter       
    
    
    
    counter.get(); // 0
    
    counter.set( 3 );
    
    counter.increment(); // 4
    
    counter.increment(); // 5
    
    
    
    counter.i; // undefined i   counter   
    
    i; // ReferenceError: i is not defined (          )
    拡大して読む
    もっと多くのことを知りたいなら、特に関数とモジュールモードの内容については、次の文章を読むことをお勧めします.
    ECMA-622-3 in detail.Chapter 5.Functions.-Dmitry A.Soshnikov Functions and function scope-Mozila Developer Network Named function expressions-Juiry“カングクス”Zaytsev JavaScript Module Pattern:In-Depth-Ben Cherry Cloures explined with JavaScript-Nick Morgan