Replacing repetitively occuring loops with eval in Javascript - good or bad? - javascript

I have a certain loop occurring several times in various functions in my code.
To illustrate with an example, it's pretty much along the lines of the following:
for (var i=0;i<= 5; i++) {
function1(function2(arr[i],i),$('div'+i));
$('span'+i).value = function3(arr[i]);
}
Where i is the loop counter of course. For the sake of reducing my code size and avoid repeating the loop declaration, I thought I should replace it with the following:
function loop(s) {
for (var i=0;i<= 5; i++) { eval(s); }
}
[...]
loop("function1(function2(arr[i],i),$('div'+i));$('span'+i).value = function3(arr[i]);");
Or should I? I've heard a lot about eval() slowing code execution and I'd like it to work as fast as a proper loop even in the Nintendo DSi browser, but I'd also like to cut down on code. What would you suggest?
Thank you in advance!

Why not just put the body of the loop into a function?
function doSomething(i, arr) {
function1(function2(arr[i],i), $('div'+i));
$('span'+i).value = function3(arr[i]);
}
and call it in the loop:
function loop() {
for (var i = 0; i <= 5; i++) { doSomething(i, arr); }
}

Gah!
This is a good question, but no, don't ever do that. Using eval in general is not recommended, as you won't see parse errors at load time, only at run time (harder to debug), it's harder to understand what's in scope when (harder to write), and you lose all your toolchain support (syntax highlight, script debugging).
Fortunately, since Javascript is basically a functional language, why not create a function that encapsulates what you want to do, and just call that?
function doMyThingNTimes(n, arr) {
for (var i=0;i <= n; i++) {
function1(function2(arr[i],i),$('div'+i));
$('span'+i).value = function3(arr[i]);
}
}

This is a dreadful idea.
It is inefficient
It is harder to debug
If you are concerned about bandwidth then use minification and HTTP compression.

Uh, no. eval should be treated as close to a last resort. JavaScript functions are First Class Objects so I would just declare whatever functions you need and pass them as one of the params.

Why not:
function loop(s) {
for (var i=0;i<= 5; i++) { s(i); }
}
loop(function4() {
function1(function2(arr[i],i),$('div'+i));$('span'+i).value = function3(arr[i]);
});

Related

Array for-loop: temp save the Array[i] or keep calling Array[i] ? Which is better/faster?

I'm trying to find out if I should temporally copy an array item while I work with it inside a for-loop.
Is there any performance difference ? Other than making the code more readable.
(JavaScript)
var max = someArray.length;
for (var i = 0; i < max; i++) {
// Here I will use someArray[i] quite often. Like this:
if (someArray[i].position.y > blabla) {
//...
}
}
OR:
var max = someArray.length;
for (var i = 0; i < max; i++) {
var tmp = someArray[i]; // <---- CHANGE
// Here I will use tmp quite often. Like this:
if (tmp.position.y > blabla) {
//...
}
}
Caveat: Worry about performance when you have a specific performance problem to worry about. Until then, write whatever seems clearest and least error prone to you and your team. 99.999999% of the time, the specific performance of a given loop just won't matter in real world terms.
With that said:
With modern JavaScript, I'd probably use a for-of loop (ES2015+) instead:
for (const entry of someArray) {
if (entry.position.y > blabla) {
// ...
}
}
In theory, that uses an iterator behind the scenes, which involves function calls; in practice, it's likely that if you're dealing with an actual array and that array uses the standard iterator, the JavaScript engine will be able to optimize the loop if the loop is a hot spot (and if it isn't, it's not worth worrying about).
Re your two alternatives, if i and someArray don't change in the loop and someArray is just a normal array, the JavaScript engine is likely to be able to optimize it into something like your second loop. As a matter of style, before for-of I always used a local within the loop rather than retyping someArray[i] each time, but that's just because it's easier to type tmp (or some more meaningful name) than someArray[i].
If there's a reason to believe that a specific loop is being slow (so for some reason, it's not getting optimized), then I might go with something like your second example:
for (let i = 0, max = someArray.length; i < max; i++) {
const tmp = someArray[i];
if (tmp.position.y > blabla) {
//...
}
}
But again, this is mostly a matter of style until/unless you have a specific performance problem you're diagnosing and fixing.

Are empty blocks run?

This is relevant, b.c. I want to test looping structures. What I normally do is put in a simple statement like
i++
in the loop. I do this b.c. I wonder if a smart interpreter will not run empty blocks. For example.
for(var i = 0; i < 10; i++) {
}
might not loop at all as there is nothing in the loop.
so I normally do something like:
for(var i = 0; i < 10; i++) {
i++;
}
But this does test the i++ statement as well as the loop structure, which I don't want.
Here look at this. Notice the delay when trying to show the alert: http://jsfiddle.net/xs724/
for(var ii = 0; ii < 1000000000; ii++){}
alert("DONE");
I tested this in chrome. It most likely could vary from browser to browser.
JsPerf Link: http://jsperf.com/js-optimizationlooping
The answer is: You never know. There are lots of optimizations going on in modern JavaScript engines. One example is dead code elimination, which skips code that does not influence the end result.
There was a quite interesting controversy about this feature in IE9:
http://digitizor.com/2010/11/17/internet-explorer-9-caught-cheating-in-sunspider-benchmark/
But why would you want to run an empty block over and over anyway?
If you want the JavaScript interpreter to simply wait try this answers:
What is the JavaScript version of sleep()?
Sleep in Javascript - delay between actions

Sleep function in javascript - without using recursion

First of all, I've had a look on all the 'sleep' questions lying around (such as What is the JavaScript version of sleep()?) but I didn't find an acceptable solution.
I would like to make a visual education tool for all sort of algorithms. In order to do so, I'm using javascript with jQuery to display the data and paint it up nicely. In order to start it up, I want to do a sorting sample, where an array is displayed, shuffled and then sorted in a visually pleasing way. So what I want to happen is that two cells get highlighted (easy), possibly swapped (easy), and then there's a small delay before the next pair is tested (hard).
I understand there isn't an explicit 'sleep' method in javascript. However, to restructure the code into using setTimeout would imply rewriting all my algorithms recursively, which is a huge hinder (although obviously not impossible).
As a sample problem, take a look at a bubble sort sample:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
sleep(1000);
}
}
exhibit_array(arr);
}
This can obviously rewritten recursively to work with setTimeout, but to do so on all the algorithms I have in mind would take a great deal of time. Am I missing something? Is there an 'easy' way to leave the implementations as they are and place sleeps at will?
EDIT:
I found two solutions: a pretty one, and a compatible one.
The pretty one only works on firefox, I'm afraid, and makes use of the wonderful yield semantics (There is some sample explanation here: https://developer.mozilla.org/en/New_in_JavaScript_1.7). This actually solves my problem perfectly, thus:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
yield true;
}
}
yield false;
}
var bubble = bubble_sort(arr)
function gen(){
if(bubble.next()){
setTimeout(gen, 500);
}
else{
alert("Done!");
}
}
This works wonderfully for me, but does rely on the yield capability which currently is only supported on firefox. Notice that for this to work at all, you need to use <script type="text/javascript;version=1.7">. This however is perfect. It could have also worked for infinite algorithms, showing them toiling in vain if need be.
The second solution I found works as well, based on the answer below:
function bubble_sort(arr){
var q = new Array();
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
q[q.length] = [ [highlight, j-1 ], [highlight, j] ];
if(arr[j-1] > arr[j]){
swap(arr, j, j-1);
q[q.length] = [ [visible_swap, j, j-1] ];
}
}
}
return q;
}
function play(q, step){
if(q.length == 0)
return;
clear_highlights();
cmds = q.shift();
for(ind in cmds){
cmd = cmds[ind];
f = cmd.shift();
f.apply(null, cmd);
}
setTimeout(function(){ play(q, step); }, step);
}
This works as well. This is pretty bothersome syntactically, but definitely works well on all browsers.
After all this though, it seems there are javascript 'extensions' which implement sleep-like syntax, which is obviously better than all of the above.
Thanks for the help!
Recently I made a visualization of sub-palindrome finder algorithm, it used setTimeout and didn't require rewriting of the algorithm in recursive form.
See this example.
The general principle is to build up a stack of commands, for bubble sort that would be a stack of highlight and swap commands. Then you can have a function running each N milliseconds which takes a command from the stack and visualizes it.
commands = [
['highlight', 1, 5]
['swap', 1, 5]
['highlight', 3, 7]
...
];
setInterval(function() {
var cmd = commands.shift();
visualize(cmd);
}, 1300);
In my problem the finder algorithm was written in Python and was provided by the user, and I couldn't modify it. Fortunately Python allows to overload access and comparison operators and record each action the algorithm takes. RecString class. In JavaScript you can't do that, but that's not a problem in your case, because you can modify the original algorithm.
I can email you the JS source if you want, it was written in haste, but might be useful anyway.
Another idea - StratifiedJS. Here's a simple jsFiddle example:
<script src="http://code.onilabs.com/apollo/0.13/oni-apollo.js"></script>
<script type="text/sjs">
for (var i = 1; i < 4; i++) {
alert(i);
hold(1000);
}
</script>
I would work with setTimeout, I believe that is the closest you are going to get to a "sleep" equivalent on the client-side.
This answer doesn't solve the general case, but perhaps you can increment the interval for each instruction so that they run one second after each other.
function bubble_sort(arr){
var interval = 0; // increases with each loop
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
(function(i, j) {
setTimeout(function() {
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
}, interval);
})(i, j);
interval += 1000;
}
}
exhibit_array(arr);
}
Thus, the first operation runs at once, the next runs after one second, the thrid after a total of two seconds, etc.
This solution provides the benefit of minimal code rewriting: just wrap your loop contents in a setTimeout (which is wrapped inside a closure with your loop variables) and add a line to increment interval after each loop iteration.
Using setTimeout() is not recursion.
You can work with a closure to keep track of state. The for loops, however, have to be changed into while for this to work:
function bubbleSort(arr) {
(function(i, j) { // <- this closes over i and j
function nextSortStep() {
while (i < arr.length) {
while (j < arr.length) {
highlight(j - 1);
highlight(j);
if (arr[j - 1] > arr[j]) {
visibleSwap(arr, j, j - 1);
}
j++;
return setTimeout(nextSortStep, 1000);
}
i++;
j = 1;
return setTimeout(nextSortStep, 1000);
}
exhibitArray(arr);
}
nextSortStep();
})(0, 1); // <- loop initialization
}
As an aside, JavaScript is not PHP, function names generally are in camelCase.
Following Lebedev's idea, I would store the "evolution of the sorting of the array" and then use setInterval() to show them.
http://jsfiddle.net/mari/EaYRZ/

Run time optimisation in Javascript

Do the main Javascript interpreters have any built in optimisation at all? I'm thinking of very simple cases like
while(i < array.length) { ... }
your code can be optimize, if that's what you're asking.
var ln = array.length; // save length into local variable to reduce scope
while(ln--) { ... } // only one value is evaluated in while statement

Dynamically Change HTML DOM event

I am trying to dynamically change an element's onClick event and I have something like the following:
for (var i = 1; i < 5; i++)
{
getElementById('element' + i).onclick = function() { existingFunction(i); return false; };
}
Everything seems to work fine apart from the fact that the argument passed to 'existingFunction()' is the final value of i=4 each time it is called. Is there a way to bind a function to onclick that uses the value of i at the time of binding as opposed to what it seems to be doing at the moment and referencing the original i in the for-loop.
Also is is there a way of performing the same bind without having to create anonymous functions each time? so that I can directly reference 'existingFunction' in each onclick for performance reasons?
Cheers guys,
Yong
Change
for (var i = 1; i < 5; i++)
{
getElementById('element' + i).onclick = function() { existingFunction(i); return false; };
}
to
for (var i = 1; i < 5; i++)
{
getElementById('element' + i).onclick = createOneHandler(i);
}
function createOneHandler(number){
return function() {
existingFunction(number);
}
}
and it should work fine.
Working Demo
A good explanation is given here
JavaScript, time to grok closures
for the i being always 4, you have a scoping problem, I advise to read this. Scoping is are really important concept, so you have better to make sure to understand what's is going on.
a better code would be
for (var i = 1; i < 5; i++)
{
getElementById('element' + i).onclick = existingFunction;
}
the onclick would pass an event has argument so you can know what element have been clicked
i.e.
function existingFunction(event){
// DO something here
}
you can read more about events there. IE does have the exact same event model as other browser so you would have to handle it.
Last bit, I advise you to use a JS framework(Jquery,ExtJS,DOJO,Prototype...) because it would simplify your task
the code you posted should work the way you intended, your problem with i=4 is elsewhere. edit: this is wrong, rageZ is right about the scoping problem.
re the other question: all you can do is offload the verbosity with
var f = function (i) { return function () { existingFunction(i); return false; } }
for (...) { document.getElementById(...).onclick = f(i); }
BTW, you should use something like jQuery for DOM manipulation (concise syntax), and perhaps Zeta (http://codex.sigpipe.cz/zeta/) for the function composition
var f = compose(false_, existingFunction);
for (...) { $(...).click(f(i));
Hooray! It's loop closures again! See 422784, 643542, 1552941 et al for some more discussion.
is there a way of performing the same bind without having to create anonymous functions each time?
Yes, in ECMAScript Fifth Edition you get function.bind:
for (var i = 1; i < 5; i++)
document.getElementById('element'+i).onclick= existingFunction.bind(window, i);
In the meantime since browsers don't yet generally support it you can monkey-patch an alternative implementation of bind (see the bottom of this comment for one such) built out of anonymous functions as a fallback.
Alternatively, assign the same event handler function to every element and just have it look at this.id to see which element number it is.

Categories

Resources