当我单击它是最后一个可能的值时

when i click it's the last possible value

本文关键字:最后一个 单击      更新时间:2023-09-26

在一切之前,ty为菜鸟问题提供帮助,对不起。

我对 for 中的事件有问题。DOM 是这样的:

<div class="wrap">
  <div class="trigger">...</div>
  <div class="trigger">...</div>
  <div class="box">...</div>
  <div class="box">...</div>
</div>

我的 JS jQuery 是:

for( i = 0; i < $('.trigger').length; i++ ){
$('.trigger:eq('+i+')').click(function(){
    $('.box:eq('+i+')').fadeIn();
});
$('.box:eq('+i+') .bt-close').click(function(){
    $('.box:eq('+i+')').fadeOut();
});
}

好吧,问题是,当我单击触发器时,i 的值为 2。我不想使用触发器 1、触发器 2...因为我不知道最终版本中会有多少。

function createEffects(index) {
    $('.trigger:eq(' + index + ')').click(function() {
        $('.box:eq(' + index + ')').fadeIn();
    });
    $('.box:eq(' + index + ')').click(function() {
        $('.box:eq(' + index + ')').fadeOut();
    });
}

for (i = 0; i < $('.trigger').length; i++) {
    createEffects(i);
}​

我会尽可能避免使用闭包。下面是一个没有它们的示例:http://jsfiddle.net/JBbQk/

问题出在闭包上。循环中的函数将记住变量i围绕它的作用域,而不是它的值。调用函数时,循环已经退出,变量值是最后一个。相反,让函数获取值本身。通常的方法是使用另一个变量。一种方法是如@JoeTuskan所示。另一种方法是使用自执行的匿名函数:

for( i = 0; i < $('.trigger').length; i++ ){
  (function(j) {
    $('.trigger:eq('+j+')').click(function(){
      $('.box:eq('+j+')').fadeIn();
    });
    $('.box:eq('+j+') .bt-close').click(function(){
      $('.box:eq('+j+')').fadeOut();
    });
  })(i);
}

这里的区别在于外部匿名函数(立即包装循环内容的函数)根本不访问循环变量,因此不会捕获它。而是使用参数调用它,该参数的值在函数内不会更改,然后由内部函数捕获。

这并不是说你不能在循环中创建函数;但是如果你这样做,你希望有一个闭包来捕获它们和循环之间的循环变量。创建闭包的函数是外部定义的(如@JoeTuskan的示例)还是内部定义的(如我的示例)是一个风格问题;只要你明白它为什么会这样工作。实际上,他帖子中解释的方式应该比这个快一点,因为通过这种方式你可以不断创建 N 个匿名函数,但我相信以这种方式可能更容易理解实际发生的事情。

这种行为背后的原因是,这些function(){...}是闭包。简而言之,当你创建一个闭包时,javascript 解释器会在函数声明点复制环境,从而允许函数访问它们,即使它们超出了范围(并且在没有闭包的情况下会被垃圾回收)。

您面临着一个可能的缺点:闭包接收对象的副本,它们只能访问变量。考虑一个例子:

var i=0;
var closure = function() {alert(i);}
closure(); //alerts 0
i=1;
closure(); //alerts 1;

在您的示例中也会发生同样的情况。for 循环运行到最后,i具有$('.trigger').length值。

所以,实现你想要的正确方法是乔·图斯坎的答案

使用每个的另一种方法:

var triggers = $('.trigger');
var boxes = $('.box');
triggers.each(
    function( ind ){
        var box = boxes.eq(ind);
        $(this).on("click", 
            function(){
                box.fadeIn();
            }
        );
    }
);
boxes.find(".bt-close").on("click", 
    function(){
        $(this).closest('.box').fadeOut(); //might be better to use parents(".box") - depends on HTML
    }
);