繁体   English   中英

setTimeout 和匿名函数问题

[英]setTimeout and anonymous function problem

这是我的代码,SetOpacity 被错误的值调用,为什么?

function SetOpacity(eID, opacity){                  
   eID.style.opacity = opacity / 100;
   eID.style.filter = 'alpha(opacity=' + opacity + ')';
}
function fade(eID, startOpacity, endOpacity){           
    var timer = 0;
    if (startOpacity < endOpacity) { 
       for (var i = startOpacity; i <= endOpacity; i++) {
           setTimeout(function() {SetOpacity(eID, i);}, timer * 30);
           timer++;
        }
    }           
}

这应该有效:

for (var i = startOpacity; i <= endOpacity; i++) {
    (function(opacity) {
        setTimeout(function() {SetOpacity(eID, opacity);}, timer * 30);
    })(i);
    timer++;
}

其工作原理如下:

  • 在循环内,您创建一个匿名函数( function(...){...} )并立即使用参数调用它(这就是function(){}周围有括号的原因,因此您可以通过添加()来调用它最后并传递参数)
  • 传递给这个匿名函数的参数(在这种情况下i ,它是函数内部的opacity )是这个匿名函数的本地参数,所以它们在循环的下一次迭代中不会改变,你可以安全地将它们传递给另一个匿名函数( setTimeout的第一个参数)

您的原始版本不起作用,因为:

  • 传递给setTimeout的函数包含对变量i引用(不是它的),并且仅在调用此函数时才解析其值,而不是在将其添加到setTimeout
  • 这个变量的值在循环中被改变,甚至在第一个setTimeout执行之前, i就已经达到了endOpacityfor循环的最后一个值)

不幸的是 JavaScript 只有函数作用域,所以如果你在循环内创建变量并分配一个新的实际值,它就不会工作,因为只要函数中有一些var ,这些变量就会在函数执行时创建(和默认情况下undefined )。 创建新作用域的唯一(简单)方法是创建一个函数(可能是匿名的)并在其中创建新变量(参数也是变量)。

这是一个关闭问题。 当您运行该函数时, i已经处于endOpacity 通过创建另一个闭包,这将起作用:

function SetOpacityTimeout(eID, opacity, timer){
  setTimeout(function() {SetOpacity(eID, opacity);}, timer * 30);
}

function fade(eID, startOpacity, endOpacity){           
    var timer = 0;
    if (startOpacity < endOpacity) {
       for (var i = startOpacity; i <= endOpacity; i++) {
          SetOpacityTimeout(eID,i,timer);
          timer++;
        }
    }           
}

Kobi 在这个问题上有正确的想法。 不过,我建议您改用间隔。

这是一个示例:(您的 SetOpacity 函数保持不变,我在这里省略了它。)

function fade(eID, startOpacity, endOpacity){
    var opacity = startOpacity;
    SetOpacity(eID, opacity);

    var interval = window.setInterval(function(){
        opacity++;
        SetOpacity(eID, opacity);

        // Stop the interval when done
        if (opacity === endOpacity)
            window.clearInterval(interval);
    }, 30);
}

这是我与 jquery 一起使用的示例。 "menuitem" 是 itemclass,jquery 检查 "recentlyOut" 类,看它是否需要向上滑动。

代码不言自明。

$(".menuitem").mouseenter(
function(){
    $(this).addClass("over").removeClass("out").removeClass("recentlyOut");
    $(this).children(".sub").slideDown();
}); 
    $(".menuitem").mouseleave(
function(){

    $(this).addClass("out").addClass("recentlyOut").removeClass("over");
    setTimeout(function()
        {
            var bool = $(".recentlyOut").hasClass("over");
            if (!bool)
            {
    $(".recentlyOut").removeClass("recentlyOut").children(".sub").slideUp();
            }
        }
    , 400);
}
    );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM