0

これが私が達成しようとしていることです: 次のmappings2オブジェクトでは、キーはいくつかのグループ化されたラジオ ボタンの名前プロパティであり、値は最初の文字列がラジオにアタッチされているクラスであるリストです (複数の可能性があります)。そのグループの、このラジオ ボタンを special-radio と呼びましょう。2 番目の文字列は、special-radio がクリックされたときに要素を有効にする必要があるクラスです。以下のコードは、ラジオのグループの変更イベントを切り替えて、特別なラジオがクリックされたときにいくつかのコードを実行し、そのグループの他の非特別なラジオがクリックされたときに別のコードを実行します。

var mappings2 = {
        // Group's name            special-radio's class      other radios       
        'DependientesEconomicos': ['hijos-dependientes', 'cuantos-hijos'],
        'Preparatoria': ['otra-prepa', 'nombre-prepa'],
        'ReproboAlgunaMateria': ['reprobo', 'causas-reprobo']
        //'CausasReprobo': ['otra-causa-reprobo', 'otra-causa-reprobo-text']
    };

(function (maps) {
        for (grupo in maps) {
            $('input[name="' + grupo + '"]').change(function (e) {
                if ($(this).attr('class') === maps[grupo][0]) {
                    console.log(grupo + ' ' + $(this).attr('class') + ' true');
                    $('.' + maps[grupo][1]).attr('disabled', false);
                } else {
                    $('.' + maps[grupo][1]).attr('disabled', true);
                    console.log(grupo + ' ' + $(this).attr('class'));
                    $('.' + maps[grupo][1]).val('');
                }
            });
        }
    })(mappings2);

コードは 1 つのエントリに対しては正常に機能mappings2しますが、さらに追加すると最後のエントリのみが機能し、前のグループの無線の 1 つをクリックすると、ログに正しいクラスが表示grupoされますが、それが属するグループではなく、最後のエントリが表示されます。エントリのグループなので、それがすべてのバグの原因です。私の質問はその理由です。

jquery1.5.1

ありがとう。

4

1 に答える 1

3

どうしたの?

この問題は、クロージャの動作方法が原因で発生します。すべての「change」関数は同じgrupo変数を参照するため、最終的な値が何であれ、すべてのコールバックが参照する値になります。

これは、ここで説明したのと同じ質問/問題です(そして同じ解決策があります):
ループ内のJavaScriptクロージャ–単純な実用的な例

詳細な説明:

同じ問題を示す簡単な例を次に示します。http:
//jsfiddle.net/Sly_cardinal/PM2Gf/6/

HTML:

<div class="wrong" style="border: 1px solid red">
    <p>Incorrect: Clicking any item will show the last value of 'i'. i.e. class='11'</p>
    <div class="1">a</div>
    <div class="2">b</div>
    <div class="3">c</div>
    <div class="4">d</div>
    <div class="5">e</div>
    <!-- snip 5 other elements. -->
    <p class="result"></p>
</div>

Javascript:

// Setup click handlers for the 'incorrect' divs.
for (var i = 1; i <= 10; i++){
    $(".wrong ."+i).click(function(){
        var t = $(this).text();
        
        // This doesn't work because all of the handlers reference the same 'i' variable.
        // When the loop finishes 'i == 11' so when you click on any of the divs they output the current value of 'i' which is eleven.
        $(".wrong .result").text("You clicked div: class='"+i+"' content='"+t+"'");
    });
}

divの1つをクリックすると、リスト内のその位置が出力されます。したがって、「e」をクリックした場合は、要素をクリックしたことを示しますclass='5'

しかし、これは起こりません-クリックしたすべてのアイテムは、それがそうであると誤って言いますclass='11'

これが発生する理由は、すべての変更関数が同じi変数を参照しているためです(「grupo」変数と同じように)。したがって、ループが最終的に終了iすると、値は11になります。したがって、すべてのdivは、値iが11である出力を出力します。


それを修正する方法:

これは、エラーを修正するためにイベントハンドラーを作成する方法を変更する方法を示しています:http:
//jsfiddle.net/Sly_cardinal/mr6ju/2/

更新されたJavaScript:

// Setup click handlers for the 'correct' divs.
for (var i = 1; i <= 10; i++){
    
    // 1. Create an anonymous self-invoking function that
    // returns a function.
    var callback = (function(){
        
        // 2. Copy the current value of 'i' to a new variable so
        // that changes to 'i' cannot affect us.
        var currentI = i;
        
        // 3. Return the function definition that
        // will be bound to the event listener.
        return function(e){
            var t = $(this).text();
            
            // 4. NOTE that we reference 'currentI' and not 'i' here.
            $(".result").text("You clicked div: class='"+currentI+"' content='"+t+"'");
        };
    }());
    
    $("."+i).click(callback);
}​

この問題を修正するには、現在の値がで新しいクロージャを設定する追加の内部関数を作成する必要がありiます。iこの内部関数は、の値をと呼ばれる新しい変数にコピーし、の代わりにcurrentI参照する新しい関数を返します。currentIi

値を新しい変数(内部関数内にのみ存在する)にコピーすることにより、への変更がi他の変数に影響を与えるのを防ぎます。

grupoこれらの例から、コードを調整して、の値を新しい変数にコピーし、イベントリスナーとして割り当てた新しい関数を返す新しいネストされた関数を作成できるはずです。

于 2012-09-04T02:43:45.983 に答える