2012-08-16 15 views
5

さて、私はこの質問のタイトルをどのようにフレーズするかわかりません。クロージャスコープはキャプチャされませんか? - Coffeescript

openDir = (path) -> 
socket.emit "get_metadata", path, (data) -> 
    columnBox = $ "<div/>", class: "columnbox" 
    for item in data.contents 
     itemBox = $ "<div/>", class: "itembox" 
     itemBox.click -> 
      columnBox_inner.children().removeClass "selected" 
      itemBox.addClass "selected" # <<<--- Over here 
      openDir item.path 
     columnBox.append itemBox 
    columnBox.appendTo "#columnscontainer" 

私は変数itemBoxがここopenDirの範囲に定義されていることを理解しています。しかし、指摘された行がラムダ関数にあるので、itemBoxは、参照される最後のオブジェクトに変更されるのではなく、親スコープのitemBoxによって参照されるオブジェクトをキャプチャするべきではありませんか?

明らかに言えば、私はそれぞれitemBoxのクリックハンドラが自分自身にaddClass "selected"を実行すると期待しています。しかし、クリックハンドラのそれぞれのitemBoxは、常に最後のitemBoxを参照します。

itemBoxが宣言される場所を変更することで、これを簡単に修正できます。すなわち

data.contents.forEach (item) -> 

for item in data.contents 

を変更しかし、私はラムダ関数は、変数の現在値をキャプチャしていない理由を知りたいのですが。

+0

質問は 'openDir item.path'行で参照される' item'変数にも適用され、 'openDir'のスコープで定義されています。 –

答えて

9

このループ:|スクリプトスコープあなたは(Javaのコーヒー)に慣れていない場合

for item in data.contents 
    itemBox = $ "<div/>", class: "itembox" 

はやや欺瞞です。スコープは、実際にはより次のようになります。

itemBox = undefined 
for item in data.contents 
    itemBox = $ "<div/>", class: "itembox" 

のでそこだけ1 itemBox可変であり、その同じ変数は、ループの各反復で使用されます。クリックハンドラはitemBoxへの参照を保持しますが、クリックハンドラが呼び出されるまで変数を評価しないため、すべてのハンドラは同じitemBox値で終了し、ループの最後にはitemBoxの値になります。 fine manualから

機能を生成するために、JavaScriptのループを使用して、それがループ変数がオーバー閉じているし、生成されたすべての機能だけでないことを確実にするために閉鎖ラッパーを挿入するのが一般的です最終的な値を共有する。 CoffeeScriptは、doキーワードを提供します。これは、渡された関数を直ちに呼び出し、引数を転送します。

だから、これを行うことができます:

for item in data.contents 
    do (item) -> 
     # As before... 

itemBoxが個別にループの各反復にスコープあなたを取得します。 forEachを使用して

:あなたが効果的にループの体としての機能を使用していて、その関数内の任意の変数は、その関数にスコープされますので、代わりに単純なループの

data.contents.forEach (item) -> 

作品

+0

私はスコープ部分について知っていました。しかし、あなたが言及したことは、 'クリックハンドラは' itemBox'への参照を保持しますが、**はクリックハンドラが**呼び出されるまで変数を評価しません。 'は、私が知らなかったものです。私は、変数が指すオブジェクトへの参照がクリックハンドラによって保持されていると仮定していました。ありがとう! –

関連する問題