Use recursion instead of EVAL
I have a list of items in a page that must be hidden in sequence, but just after the previous item has been totally hidden.
I made the following code, where I create a big s开发者_运维技巧tring inserting the callbacks inside the previous callbacks and later use eval to execute the effects, but despite the code is working fine as expected, I'm totally sure that's not the best way to do this.
// get items to hide
var itemsToHide = jQuery(".hide");
// function responsible to hide the item
var hideItem = function (item, callback) {
jQuery(item).hide(100, callback)
};
// declare an empty function, to be the first to be called
var buff = function(){};
for (var i = 0; i < itemsToHide.length; i++) {
// put the previous value of buff in the callback and assign this to buff
buff = "function(){hideItem(itemsToHide[" + i + "], " + buff + ");}";
}
// execute the effects
eval("(" + buff + ")()");
Any suggestion on how to accomplish this effect using recursion, without the "evil" eval?
Hiding with recursion - functional style
In this case you know the duration of the effect, so you can do as others suggested.
However you might still want to know how to achieve the same using a more functional style, using a simple recursion.
So here I show you a way to do that.
1. The code
<script src="http://code.jquery.com/jquery-latest.pack.js"></script>
<script type="text/javascript">
$(function() {
var items = jQuery(".to-hide");
(function hideRec() {
if (items.length == 0) {
window.alert("The end.");
return;
}
var toHide = jQuery(items[0]);
items = items.slice(1);
toHide.hide("100", hideRec);
})();
});
<script>
<ul>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<li class="to-hide">...</li>
<ul>
2. How does it work?
We first obtain, from jQuery, an array containing the objects we want to-hide
.
Then we create a named anonymous function that will be executed right after its definition -- it's the (function() { ... })();
pattern. Even if it is an anonymous function, we give it a name so that we are able to easily call it recursively.
Note that you can achieve the same thing without giving an anonymous function a name -- which may sound a little strange if you don't understand how JavaScript deals with scope -- with the more obscure version:
(function() { // Anonymous function without a name
if (items.length == 0) {
window.alert("The end.");
return;
}
var toHide = jQuery(items[0]);
items = items.slice(1);
toHide.hide("100", arguments.callee); // Recursive call to anonymous function
})();
This time we used the fact that arguments.callee
represents the function itself -- so no need to give an anonymous function a name.
The whole magic is inside this recursive anonymous function -- that is a closure.
The hideRec
anonymous function captures the items
array. After checking that there's still something inside, it will remove the first element and store it in the local toHide
variable (properly wrapped with jQuery).
At the end, it uses jQuery to hide the element, and passes this anonymous function as the callback -- jQuery will call it again once it has finished the effect.
I hope this is clear enough.
Good luck!
Since you know the number of milliseconds each one takes to hide, you don't need to use a callback at all:
jQuery(".hide").each(function(i)
{
var obj = $(this);
setTimeout(function() { obj.hide(100); }, i * 100);
}
精彩评论