2012-02-19 2 views
0

私はjQuery.liveのような関数を構築しようとしています。 Helperは、_liveEvent_addEventListenerのメソッドを持つクラスです。 Helper._addEventListenerはW3C addEventListenerのCrossBrowserバージョンです。DOMイベントコールバック内にクロージャが必要ですか?

Helper.prototype._liveEvent = function(type, evt, ofunc) { 
    var elHand = document; 
    type = type.toUpperCase(); 

    this._addEventListener(elHand, evt, function(me) { 
     // Inside here I use the `type` variable. 
     // I don't know why but it works. 

     for (var el = me.srcElement; el.nodeName !== 'HTML'; 
      el = el.parentNode) 
     { 
      if (el.nodeName === type || el.parentNode === null) { 
       break; 
      } 
     } 
     if (el && el.nodeName === type) { 
      ofunc.call(el, me); 
     } 

    }); 
}; 

私はさまざまな種類のHelper._liveEvent機能を2回実行していますよ。そしてそれはうまく動作します。私は、type変数が_liveEventコンテキスト内に設定されているので、_addEventListenerコールバックはその変数の最後のバージョンしか見ることができないと考えました。しかしそれは事実ではない、それは正常に動作しているようだ。

私の質問は以下のとおりです。

  • _addEventListenerコールバックは、タイプの両方のバージョンを見ることができるのはなぜ?
  • 私のコードはメモリをリークしているのですか?

UPDATE

この他の例では、私は、このより良い理解しました。しかし、私はまだそれを食べるのか分からない。

function foo(i) { 
    setTimeout(function() { 
     console.log(i); 
    }, 400); 

} 

// Prints 1, 2, 3 
for (var i = 1; i < 4; i++) { 
    foo(i); 
} 

function bar() { 
    for (var i = 1; i < 4; i++) { 
     setTimeout(function() { 
      console.log(i); 
     }, 400); 
    } 
} 

// Prints 4, 4, 4 
bar(); 
​ 

答えて

1
  • 別々の閉鎖範囲は、それぞれがelHandtypeの独自の値を持つ、_addEventListener()に渡された匿名関数のインスタンスごとに作成されるからです。
  • 「漏れ」という言い方によって異なります。すべてのクロージャは、それが含んでいるオブジェクトがGCで処理されるのを防ぎます。クロージャは、それを参照するオブジェクト(あなたのような匿名関数など)がなくなるとGC'edされます。この意味では、追加されたリスナー(匿名関数)を削除する方法がないため、関連付けられたスコープオブジェクトをGCに適格にすることができないため、メモリリークが発生します。
+0

私は匿名関数を複数回作成したのではなく、複数の入力で_liveEventを複数回呼び出すため、変数に正しいスコープがあると思います。 – Eduardo

+0

複数の '_liveEvent()'呼び出しを示唆しているのと同じことが、ここでは同じです(それぞれ "elHand"と "type"の値を持っています)。 '_addEventListener()'への2回の連続した呼び出しで追加されたリスナーは、2つの異なるFunctionオブジェクトです。 –

+0

私の2番目の例を見てください。タイムアウトのあるもの。 fooとbarの両方が複数の無名関数を生成しますが、1つのみが動作します。スコープは、foo関数のパラメータによって保持されます。無名関数の作成ではありません。 – Eduardo

1

効果的に、あなたは既にクロージャを作成しています。匿名関数を呼び出すi現在値にidセットで新しいクロージャを作成します -

for(var i=0; i<10; i++) { 
    elem.onclick = (function(id) {alert(id);})(i); 
} 

作品は:理由はここにあります。 (個人的には、私が使用したい変数と同じものを引数と呼ぶのが好きなので、その関数の変数の値を「ロックする」と考えることができます)。

メモリリークが発生する限り、2回の呼び出しではリークが発生しません。 GCは私が思うように動作する場合、それらにポインタを持たないクロージャをすべて削除します。特に、ページを終了すると、そのページに関連付けられたメモリが解放されます。

+0

ありがとうございます。私は閉鎖の仕組みを知っていますが、この特定のケースは私を疑問に思いました。私は決して匿名の関数を実行しないからです。 – Eduardo

関連する問題