0

这是我要完成的工作:在以下mappings2对象中,键是一些分组单选按钮的名称属性,值是一个列表,其中第一个字符串是一个附加到收音机的类(可能不止一个)在该组中,我们将此单选按钮称为特殊单选,第二个字符串是一个类,其元素必须在单击特殊单选时启用,下面的代码应该在一组单选的更改事件之间切换,让单击特殊无线电时执行一些代码,单击该组中的其他非特殊无线电时执行不同的代码。

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);

该代码适用于一个条目,mappings2但是当您添加更多时,只有最后一个条目有效,如果您单击以前组中的一个收音机,日志会显示正确的类,但grupo不是它所属的组,它会显示最后一个条目的组,所以这是所有错误的来源,我的问题是为什么。

jQuery 1.5.1

谢谢。

4

1 回答 1

3

有什么问题?

问题是由闭包的工作方式引起的。您所有的“更改”函数都引用同一个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 时,我们希望它打印出它在列表中的位置。因此,如果您单击“e”,我们希望它说我们单击了带有 的元素class='5'

但这不会发生 - 您错误地单击的每一个项目都说它是class='11'

发生这种情况的原因是因为所有更改函数都引用了相同的i变量(就像您的“组”变量一样)。因此,当循环最终完成时i,值为 11。因此,所有 div 打印出的值为i11。


如何修复它:

这显示了如何更改创建事件处理程序以修复错误的方式: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 回答