2009-08-21 4 views
4

何らかの理由で、何があっても、pageNumberはloopCounterのループの最後の値になります。今私は、closure自体でloopCounterを直接使用していたのですが、私は理解できません。下のコードからわかるように、私はclosure内にloopCounterの現在の値をとるための新しい変数を作成しています。修正された閉鎖問題への可能なアクセス...どのように殴る?

(私が考えることができるのは、javascriptがすべてを参照型として扱うと仮定した場合です)、pageNumberはloopCounterへの参照を取っているので、新しいpageNumberを何回作成しても常にloopCounterオブジェクトを指します。したがって、loopCounterがどのような値で終わっても、pageNumberが指す値になります。

どのようにしてloopCounterをポイントしないようにしますか?現在のloopCounter値を保持する反復ごとに新しいpageNumberを作成しますか?以下のカップルの答えに

for (var loopCounter = result.StartingPoint; loopCounter <= result.HighestPageCount; loopCounter++) 
{ 
    ... 
    var newDiv = document.createElement('div'); 
    ... 
    //trying to remove the reference to loopCounter 
    var pageNumber = loopCounter; 
    newDiv.onclick = 
    function(event) 
    { //Right here ---V 
     getResultUsingUrl(result.PagerPreLink + "&pageNumber=" + pageNumber); 
    }; 

    ... 
} 

SOLUTION

ありがとう:

function createClickMethod(loopCounter, link) 
{ 
    var pageNumber = loopCounter; 

    return function(event) { getResultUsingUrl(link + "&pageNumber=" + pageNumber); }; 
} 

と私は次のように呼び出すことができます。

newDiv.onclick = createClickMethod(loopCounter, result.PagerPreLink); 

または私はjQueryのを使用したい場合は...以下に示す:

jQuery(newDiv).click 
(
    createClickMethod(loopCounter, result.PagerPreLink) 
); 
+0

result.StartingPointは何を書くことができますか? –

+0

非同期メソッド呼び出しから返されたオブジェクトです。 –

答えて

9

誰もが、それはスコープの問題だ、言ったように。 JSライブラリを使用しないと、次のようなことができます:

newDiv.onclick = (function() { 
    var num = loopCounter; 
    return function(evt) { 
     console.log(num); 
    } 
})(); 

値の周りに別のクロージャを作成するだけで済みます。

+0

したがって、基本的には、スコープを明確にするためにイベントメソッドを作成するメソッドが必要です。 –

+0

はい。 JSスコープは関数に限定されているので、ブロックではなく新しい関数を作成する必要があります。これは本質的に、さまざまなJSライブラリがイベント接続メソッドで行うことを強制しているものです。 – seth

0

onclickクロージャは範囲を保持しないため、結果にアクセスできません。

を参照してください。その範囲を制御できるように、簡単で強力なソリューションがあります。

+0

その時点でdojo.forEachとdojo.connectを使用することができます – seth

1

結果です.StartingPointは実際にはプリミティブ型です。実際のNumber型ですか?そうでない場合は、おそらく、そのオブジェクトへの参照を取得していて、次に文字列連結がタイプ強制を行っているということでしょう。代わりにこれを試してください:

var pageNumber = new Number(loopCounter); // force coercion 
+0

これは、そのメソッドとそのメソッドがまだloopCounterを指しているだけのpageNumber参照を作成しませんか? –

5

毎回新しいpageNumberを作成しているわけではありません。あなたは1つしか持っていません。 JavaScriptのスコープは、関数スコープを超えて拡張されていません。あなたが関数内で宣言した "var"は、関数の先頭で宣言したのとまったく同じように動作します。

http://javascript.crockford.com/code.html

+0

面白い古い動的スコープ。 – Zoidberg

2

Javascriptクロージャは、変数への参照を格納するため、すべてのonclickハンドラが同じ変数を使用しています。

あなたはこのように、中間関数内で変数をキャプチャする必要があります。

その後
function buildClickHandler(pageNumber) { 
    return function(event) { //Create and return a new function 
     getResultUsingUrl(result.PagerPreLink + "&pageNumber=" + pageNumber); 
    } 
} 

、このように、onclickハンドラを作成するために、その機能を使用します。

for (var loopCounter = result.StartingPoint; loopCounter <= result.HighestPageCount; loopCounter++) { 
    //... 

    var newDiv = document.createElement('div'); 

    newDiv.onclick = buildClickHandler(loopCounter); 
} 

各呼び出しをbuildClickHandlerに作成し独自の変数を持つ別のクロージャです。


脇に、jQueryを使用してDOM操作を行うことを検討してください。生のDOM APIよりはるかに簡単です。

あなたの例では、

$('<div />').click(buildClickHandler(loopCounter)); 
+0

私は2つを正しいものとしてマークすることができました。私はあなたが提案したようにjqueryを使用する可能性が最も高いですが、これは一般的なものにしたいので、より多くの人々が答えます。 –

関連する問題