setTimeout和匿名函数问题

ron*_*nik 16 javascript

这是我的代码,用错误的值调用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++;
        }
    }           
}
Run Code Online (Sandbox Code Playgroud)

MBO*_*MBO 45

这应该工作:

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

其工作原理如下:

  • 在内部循环中你创建了一个匿名函数(function(...){...})并立即用参数调用它(这就是为什么周围有括号function(){},所以你可以调用它()在结尾添加并传递参数)
  • 传递给这个匿名函数的参数(i值,这是opacity函数内部)是这个匿名函数的本地函数,因此它们不会在循环的下一步中更改,并且您可以将它们传递给另一个匿名函数(此处setTimeout)

您的原始版本没有用,因为:

  • 你传递的函数setTimeout保存对变量的引用i(不是它的值),并在调用此函数时获取值,而不是在将它添加到setTimeout
  • 这个变量的值在循环中被改变,在你获得第一个之前setTimeout它获得endOpacity值(for循环的最后一个值)

不幸的是JavaScript只有函数作用域,所以如果你在循环中创建变量并分配新的实际值它将不起作用,因为每当有一些var内部函数时,这些变量是在函数执行时创建的(undefined默认情况下获取值) .创建新范围的唯一(简单)方法是创建函数(可能是匿名的)并在其中创建新变量(参数也是变量)


Kob*_*obi 5

这是一个封闭问题.当你运行该功能时,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++;
        }
    }           
}
Run Code Online (Sandbox Code Playgroud)

  • 你测试过这个吗?`var opacity`仍然与`i`处于相同的范围内,所以它应该仍然打破,从我所知道的. (2认同)