Here is the code which I wrote off :
1
2
3
4
5
array = [1, 9, 4, 8, 2, 3, 6]; for (i = 0; i < array.length; i++) { window.setTimeout ("console.log(array[i])", array[i]*1000); }
What the code was supposed to do was, for each integer in the array, wait for those many seconds and then print that integer. So, the integer 9 will be logged into the console after 9 seconds while the code will log 2 into the console after 2 seconds.
Here is what it logged into the console :
undefined undefined undefined undefined undefined undefined undefined
What was happening here? The line 4 in the code was telling the javascript engine that after array[i] number of seconds, evaluate the javascript code console.log(array[i]). So it was here, that all the logic was going for the toss then! In two shakes of a duck's tail, the for loop would come to a stop. Then, after a comparatively long time (1 second) the first timeout will get over and the code console.log(array[i]) will get evaluated. But wait! by this time, the value of i is 7 and each of those timeouts will end up evaluating console.log(array[7]). And we know that as the array contains only 7 elements and array[7] means the 8th element in the array, there is no doubt that undefined will be logged into the console! Mystery solved!
I read up a bit on the web about the setTimeout function and came to know that it is a bad practice to use a string as the first parameter of setTimeout for various reasons - mostly the association with eval . The syntax of setTimeout as given there is :
setTimeout (function_object, timeout_in_milliseconds, param1, param2, param3.....)
where the arguments after timeout_in_milliseconds are all optional. For example,window.setTimeout(foo, 5*1000, 99, 42)
will make a function call to foo as foo(99, 42) after 5 seconds.So I changed the code to following :
1
2
3
4
5
6
7
8
9
array = [1, 9, 4, 8, 2, 3, 6]; function log_value_in_console (value) { console.log (value); } for (i = 0; i < array.length; i++) { window.setTimeout (log_value_in_console, array[i]*1000, array[i]); }
Quite as expected, this is what it logged into the console :
1 2 3 4 6 8 9
So now the problem was to do sleep sort with just two parameters to the setTimeout function. Basically, first argument needed to be a function which somehow knows what to log. Enter closures!
What is this closure anyway? Frankly, I don't know :P. What I understand is "a closure is like a zombie, a à¤ूत!" closure is formed when a function returns (gets done with its execution) but still its scope, that is its internal variables and arguments passed to it (think of it as kind of a stack frame of that function) are not cleaned by the garbage collector. Such a scenario typically happens when the function returns another function and returned function needs to access the internal variables / arguments of the outer function. Apart from the fancy name which notoriously is name of a mathematical property also, there is nothing complex or voodoo about closures.
Using closures, I rewrote the code in following way, and as you might have guessed, it worked! :P
1 2 3 4 5 6 7 8 9 10 11 12
array = [1, 9, 4, 8, 2, 3, 6]; function make_logger_function (value) { function log_value_in_console () { console.log (value); } return log_value_in_console; } for (i = 0; i < array.length; i++) { window.setTimeout (make_logger_function(array[i]), array[i]*1000); }
Comments
Post a Comment