8

わかりました、これが問題のスクリプトです。

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = function() { alert( i ) }
    document.body.appendChild( a );
}

このスクリプトは、配列を使用して、1、2、3 の 3 つの div を生成します。
配列内の位置のインデックスを警告する各 div に (簡単にするために Dom0) クリック ハンドラーを設定しました。-そうではないことを除いて!配列の最後のインデックスである 3 を常に警告します。
これは、'alert( i )' の 'i' が外部スコープ (この場合はグローバル) へのライブ参照であり、ループの最後でその値が 3 であるためです。必要なのは、ループ内で i を逆参照する方法です。

これは1つの解決策であり、私はそれを使用する傾向があります.

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.i = i; //set a property of the current element with the current value of i
    a.onclick = function() { alert( this.i ) }
    document.body.appendChild( a );
}

他の誰かが何か違うことをしていますか?
本当にスマートな方法はありますか?
図書館がこれをどのように行うか知っている人はいますか?

4

4 に答える 4

20

この小さなクロージャー トリックを使用する必要があります。イベント ハンドラー関数を返す関数を作成して実行します。

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = (function(i) { return function() { alert( i ) } })(i);
    document.body.appendChild( a );
}
于 2009-01-14T13:46:11.883 に答える
4

私はあなた自身の解決策にとどまりますが、次のように変更します:

var links = [ 'one', 'two', 'three' ];

function handler() {
    alert( this.i );
}

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.i = i; //set a property of the current element with the current value of i
    a.onclick = handler;
    document.body.appendChild( a );
}

このようにして、1 つの関数オブジェクトだけが作成されます。それ以外の場合、関数リテラルはすべての反復ステップで評価されます!

クロージャーによるソリューションは、元のコードよりもパフォーマンスがさらに低下します。

于 2009-01-14T13:57:46.807 に答える
1

使用するリソースが少ないため、関数を 1 つ使用するChristophの方法をお勧めします。

以下は、関数に値を格納し (関数はオブジェクトであるため可能です)、argument.calleeを使用して関数内の関数への参照を取得する別の方法です。この場合、あまり意味がありませんが、他の方法で役立つ可能性があるため、テクニックを示します。

var links = [ 'one', 'two', 'three' ];

for( var i = 0; i < links.length; i++ ) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = function() { alert( arguments.callee.i ) }
    a.onclick.i = i;
    document.body.appendChild( a );
}

この手法は、関数が呼び出し間で永続的な情報を保存する必要がある場合に役立ちます。上記の部分を次のように置き換えます。

a.id="div"+i;
a.onclick = function() {
    var me = arguments.callee;
    me.count=(me.count|0) + 1;
    alert( me.i );
}

後で呼び出された回数を取得できます。

for( var i = 0; i < links.length; i++ ){
    alert(document.getElementById("div"+i).onclick.count);
}

また、呼び出し間で情報をキャッシュするためにも使用できます。

于 2009-01-14T14:15:53.557 に答える
0

RoBorg の方法は間違いなく正しい方法ですが、私は少し異なる構文が好きです。どちらも「i」を保持するクロージャーを作成するという同じことを達成します。この構文は私にとってより明確であり、既存のコードの変更が少なくて済みます。

var links = [「1」、「2」、「3」];

for( var i = 0; i < links.length; i++ ) (function(i) {
    var a = document.createElement( 'div' );
    a.innerHTML = links[i];
    a.onclick = function() { alert( i ) }
    document.body.appendChild( a );
})(i);
于 2009-01-15T00:29:13.957 に答える