簡體   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