SetTimeout and anonymous function issue

This is my code, SetOpacity is being called with wrong values, why?

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++; } } } 
+14
javascript
Jan 31 '10 at 12:12
source share
4 answers

This should work:

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

This works as follows:

  • inside the loop, you create an anonymous function ( function(...){...} ) and immediately call it with a parameter (that’s why there are brackets around function(){} , so you can call it adding () at the end and pass parameters ) Options
  • passed to this anonymous function (the value of i , which is the opacity inside the function) is local to this anonymous function, so they do not change in the next steps of the loop, and you can safely pass them to another anonymous function (this is with setTimeout )

Your original version did not work because:

  • your function passed to setTimeout contains a reference to the i variable (and not its value), and it gets the value when this function is called, not the time it was added to setTimeout
  • the value of this variable changes in the loop, and until the first setTimeout is received, it gets the value endOpacity (the last value from the for loop)

Unfortunately, JavaScript has only a scope of functions, so it will not work if you create a variable inside the loop and assign a new actual value, because whenever there is some internal var function, these variables are created during the execution of the function (and get the value undefined by default). The only (simple) way to create a new area is to create a function (it may be anonymous) and create new variables in it (parameters are also variables)

+42
Jan 31 '10 at 12:35
source share

This is a problem with closing. By the time the function starts, i already in endOpacity . This will work by creating another closure:

 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++; } } } 
+5
Jan 31 '10 at 12:16
source share

Kobe has the right idea on the issue. I suggest you use spacing instead.

Here is an example: (Your SetOpacity function remains unchanged, I left it here.)

 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); } 
+1
Jan 31 '10 at 12:34
source share

This is an example that I used with jquery. "menuitem" is an itemclass, and jquery checks the "recentOut" class to see if it needs to back up.

The code speaks for itself.

 $(".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); } ); 
+1
Jun 05 2018-11-11T00:
source share



All Articles