Javascript自己実行関数


前言
皆さんはJavaScriptを勉強する時、よく匿名関数を実行するコードに出会います.今日は主に自己実行について考えてみます.これを詳しく知る前に、「自己実行」という呼び方について話してみます.本文ではこの機能の呼び方は必ずしも完全ではなく、個人によってどう理解されているかということです.「即時呼出」という人もいます.自動実行という人もいますので、あなたの理解通りに名前を取ってもいいです.でも、多くの人が「自己実行」と呼んでいます.しかし、著者らは、「すぐに呼び出す関数式」と呼ばれるものを説得するために、多くの話をしています.
本文の英語の原文の住所:http://benalman.com/news/2010/11/immediately-invoked-function-expression/
自己実行とは何ですか?
JavaScriptでは、どのfunctionも実行時に実行コンテキストを作成します.function宣言の変数とfunctionは、このfunctionの内部だけになる可能性があります.このコンテキストは、functionを呼び出すときに、変数またはプライベートサブfunctionから作成する簡単な方法を提供します.
//    function        function,    function        i//    ,     function                。function makeCounter() {    //    makeCounter    i    var i = 0;    return function () {
        console.log(++i);
    };
}//   ,counter counter2      ,         i。var counter = makeCounter();
counter(); // logs: 1counter(); // logs: 2var counter2 = makeCounter();
counter2(); // logs: 1counter2(); // logs: 2alert(i); //     :i  defind(  i    makeCounter  )。
多くの場合、私たちはmakeCounterの複数の例を必要としないで、甚だしきに至ってはいくつかのcaseの下で、私達も表示の戻り値がいらないで、OK、下を見ます.
 
問題の核心
function foo(){}またはvar foo=function()関数のような宣言をすると、後に括弧を入れることで自己実行ができます.例えば、foo()はコードを見てください.
//            function          ()        ,  foo(),//   foo   function() { /* code */ }           var foo = function(){ /* code */ } 
// ...                   ? function(){ /* code */ }(); // SyntaxError: Unexpected token (//
上記のコードが実行されても、第2のコードがエラーになります.解析器がグローバルのfunctionまたはfunction内部のFunctionキーを解析するとき、デフォルトではfunction宣言であって、Fnction表現ではなく、コンパイラに教えないと名前のないfunctionとして宣言し、文法エラー情報をスローします.functionは名前が必要だからです.
ナレーション:関数、括弧、文法エラー(SyntaxError)
面白いことに、上の間違ったコードに名前を付けても、彼は文法の間違いを指摘します.上の原因とは違います.一つの表式の後に括弧()を入れると、すぐに実行されますが、一つの文の後に括弧()を入れると、全く違った意味です.彼はただグループ操作子です.
//     function         ,          //     ()       ,               function foo(){ /* code */ }(); // SyntaxError: Unexpected token ) //         ()        ,        //   foo        function foo(){ /* code */ }( 1 ); 
//               ,  function    ,              : function foo(){ /* code */ }
 
( 1 );
ECMA-622-3 in detail.Chapter 5.Functionsにアクセスできます. さらなる情報を取得する.
自己実行関数式
上記の問題を解決するには、非常に簡単です.コードのコードを大括弧で全部くくればいいです.JavaScriptの括弧には語句が含まれていないので、この点において、解像器はfunctionキーワードを解析する時に、相応のコードをfunction表現に解析します.
//   2   ()      (function () { /* code */ } ()); //       (function () { /* code */ })(); //           //     () JS &&,  ,                        //                     ,            //   ,            var i = function () { return 10; } ();true && function () { /* code */ } ();
0, function () { /* code */ } ();//          ,        //       function         !function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();//       ,  new   ,    ,         // http://twitter.com/kuvos/status/18209252090847232new function () { /* code */ }new function () { /* code */ } () //         ,       ()
上で述べた括弧は曖昧さを解消するものです.実は、圧迫の根は必要ではありません.括弧はもともと内部で期待されていたのは関数式です.しかし、私達は依然としてそれを使っています.主に開発者が読みやすいようにしています.これらが自動的に実行された表現に変数を与えたとき、先頭に括弧があります.(すぐに分かります.コードを最後まで引いて見ないでください.括弧があるかどうか確認してください.
クローズドで保存状態
通常のfunctionで実行されるときのパラメータと同様に、自己実行の関数式もこのようにして伝えられます.なぜなら、クローズドは直接にこれらのパラメータを参照することができます.これらのロックされた着信パラメータを利用して、自己実行関数式は効果的に状態を保存できます.
//         ,    i     locked //   ,       ,        i     //       i      //            ,       I am link #10(   10 a    )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    locked     ,         ,    i     a    (  10)//       lockedInIndex      ,          //           ,      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);

}//            ,                 //     addEventListener  //       ,          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');

}
実は、上の2つの例の中のlockedIndex変数は、iにも変えられます.外のiとは違っていますので、問題はありません.これも匿名関数+クローズドの威力です.
匿名関数の実行と、即時実行の関数表現の違い
この招待状の中で、私達はずっと自己実行関数と言っています.正確には匿名関数を実行することを提案しています.しかし、英語の原典の作者は直ちに呼び出す関数式を使用することを提案しています.
//           ,        ,  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 */ } ());//           (IIFE)      ,         (function () { arguments.callee(); } ());
(function foo() { foo(); } ());//   ,        5      ,              ,     undefined//   ,  (function foo() { foo(); } ());
ここのいくつかの例を望んで、みんなに分かることができて、何が実行しますか?
注:argments.caleeはECMAScript 5 strit modeで廃棄されていますので、このモードでは実際には使えません.
最後のナレーション:Moduleモード
このすぐに呼び出された関数式を話した時、私はまたModuleモードを思い出しました.もしまだこのモードに慣れていないなら、まずコードを見に来ます.
//                 // return    ,                //            counter,        function  var counter = (function () {    var i = 0;    return {
        get: function () {            return i;
        },
        set: function (val) {
            i = val;
        },
        increment: function () {            return ++i;
        }
    };
} ());// counter            ,                 counter.get(); // 0counter.set(3);
counter.increment(); // 4counter.increment(); // 5counter.i; // undefined   i         i; //     : i     (  i      )