2016-04-08 21 views
0

私はクロージャーに関しては概念的には手応えがありますが、私はかなり理解できない問題が生じました。クロージャに関する匿名のJavaScript関数定義の理解

それが戻るとき、これは許されていないよう最外関数の最後の値に結合することなく内部関数へのいくつかの値を渡す機能を作成する:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
      function (x) { // this anonymous function definition... 
       var item = 'item' + list[x]; 
       result.push(
        return function() { 
         console.log(item + ' ' + list[x]); 
        }; 
       ); 
      }(i);   // and simultaneous invocation... 
    } 
    return result; 
} 

一方私が移動した場合完全にコール内部の閉鎖は、すべてが正常にうまくいく)(.pushします

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
      result.push(
       function (x) { // wrapper now inside the call to .push() 
        var item = 'item' + list[x]; 
        return function() { 
         console.log(item + ' ' + list[x]); 
        }; 
       }(i)   // and called here... 
      ); 
    } 
    return result; 
} 

私は思ったんだけどは次のとおりです。どのようなルール私は違反しています私は、forループ内ですぐに閉鎖をラップ匿名関数を定義するとき.push()の呼び出しの中ではなく、 ?最初のケースで

+0

'result.push(リターン機能が動作することはありません' ...、それは閉鎖して行うことはありません;。リターンは声明で、ステートメントは無効ですので、それはdidnの場合でも、あなたがpush()でエンディングセミを持つことはできないので、最初のコードにいくつかの問題があります。 – dandavis

+0

"* this doesn – Amit

+0

*「正常に動作する」*を定義する。予想される動作は何ですか?どのようにそれぞれ異なるのですか? –

答えて

1

「許可されていません」とは、インタープリタが構文エラーについて不平を言っていると仮定しています。最初の場合の内容:

result.push(
    return function() { 
     console.log(item + ' ' + list[x]); 
    }; 
); 

構文的には有効ではありません。

しかし、たとえあなたがリターンを削除する場合:

function buildList(list) { 
    var result = []; 
    for (var i = 0; i < list.length; i++) { 
      function (x) { // this anonymous function definition... 
       var item = 'item' + list[x]; 
       result.push(
        function() { 
         console.log(item + ' ' + list[x]); 
        } 
       ); 
      }(i);   // and simultaneous invocation... 
    } 
} 

あなたはまだエラーを取得します。これは、IIFEにかっこを指定していないためです。function (x) { ... }()は、末尾の()に関係なく、宣言/ステートメントとして扱われます。しかし、関数を宣言している場合は、名前を指定する必要があります。その理由は、functionの後に(が予期せぬことが原因です。式として扱う場合は、(...)にラップして(function (x) { ... })()を使用する必要があります。

第2のケースでは、result.push(...)への引数は式でしかないため、function (x) { ... }()をどのように解釈するかについてあいまいさはありません。決して宣言ではないので、式(関数リテラルまたはIIFEのいずれか)でなければなりません。

類推のように、function() { ... }の文字列"hello"と似ています。"hello"を単独で使用することはできません。次のコードを構文的に有効なされていません。これは、あなたが匿名関数で何をしているか、本質的である

var x = "foo"; 
"hello"; 

:その機能を実行する必要があり

var x = "foo"; 
function() { 
} 

何?前の例の"hello"が何にも割り当てられていないのと同じように、何も割り当てられていません。しかし、私たちは関数が呼び出せることを知っているので、(function() { ... }())を使って何をしているのかは、「ここで定義した関数を呼び出して、今すぐ呼び出してください」と言っています。

"abcd".substring(0, 2); // returns "ab" 

そして実際、私は生命維持に何が起こっているのか少し良く示していると思う機能で同様のものを、行うことができます:それは文字列リテラルのメソッドを呼び出すことに似ている

// logs "hello" 
(function() { 
    console.log("hello"); 
}).call(); 

括弧はあいまいさを取り除き、その関数を宣言ではなく式/リテラル​​として扱いたいと通訳者に指示する方法です。上記の例では、周囲の括弧を削除した場合、予期しない文法について同じ構文エラーが発生します。(

+0

Ahhh。これは素晴らしい。明快な説明に感謝します。 –

+0

@ウィリアムM。助けてうれしい! –

+0

@VivinPaliathが間違ったIIFE呼び出しに気付いた –

0

は、あなたが効果的に第2のケースで

result.push(return function(){...})

であるあなたの関数宣言しないで呼び出し、のリターンを推進している、あなたはあなたを返す生命維持機能の実行、のリターンを推進しています元の関数は、明らかにその効果

result.push(function(){...})

ので、二つ目は、あなたが望むものです。最初に変更できるのは

result.push(
    function() { 
     console.log(item + ' ' + list[x]); 
    }; 
); 

です。いいえreturn押している間。

0

ラッパー(IIFE)関数で構文エラーが発生し、returnステートメントが最初のケースで間違って配置されました。ここでは固定の(そしてわずかに変更された)スニペットです。

function buildList(list) { 
 
    var result = []; 
 
    for (var i = 0; i < list.length; i++) { 
 
      (function (x) { // this anonymous function declaration... 
 
       var item = 'item' + list[x]; 
 
       result.push(
 
        function() { 
 
         console.log(item + ' ' + list[x]); 
 
         return item + ' ' + list[x]; 
 
        } 
 
       ); 
 
      })(i);   // and simultaneous invocation... 
 
    } 
 
    return result; 
 
} 
 

 
buildList([1,2,3]).forEach(function(func) { 
 
    
 
    document.body.innerHTML += func() + '<br>'; 
 

 
});