JavaScript Functions are Weird, Too

Remember when I said that JavaScript arrays are weird because they are also objects? Aside from their numbered elements, they can have, in addition, hash elements (a key and a value).

Believe it or not, functions in JavaScript are just as weird. They also are objects. If you have a function named bar, it can have a property named foo.

Doesn’t seem very useful, does it? After all, functions can already have variables declared inside them.

The difference? These special function elements persist from one call of the function to the next. You can use them to replace global variables that might otherwise cause unsightly clutter.

For instance, if you want a function to keep track of how many times it’s been called, this does the trick:

function add(a,b) {
  if (add.called===undefined) {
    add.called=0;
  }
  add.called++;
  return a+b;
}

or, more tersely but confusingly,

function add(a,b) {
  add.called=add.called+1 || 1;
  return a+b;
}

You don’t have to call the function by its name when you’re in the function, you can use arguments.callee instead.

How about a real world example. [Warning: You probably won’t get your money’s worth unless you compare the before-and-after code. I suggest copying and pasting them into a diff program so you can see the changes highlighted. Or you could just print out this whole blog post and take it to the bathroom.]

Alert! Unresponsive Script!

Sometimes, you might have some code that takes so long to execute that the browser alerts the user that a script has become unresponsive. That tends to take a long time for new browsers (they assume you might be running a Rich Internet Application and that such messages may be worse than the trouble they’re trying to solve), but for old browsers (like my nemesis IE6), the time is short. Something like 3 seconds.

Yummy Morsels

To solve this problem we have to break up work into bite-sized pieces.

Here’s our before case, the brute force (slow) solution to finding prime numbers. Adapted from a C version here.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
    <title><!-- Insert your title here --></title>
    <script type="text/javascript">
        function findPrimes(topCandidate) {
            var primes=[];

            candidate = 2;
            while (candidate <= topCandidate) {
                trialDivisor = 2;
                       prime = true;
                while (trialDivisor * trialDivisor <= candidate) {
                    if (candidate % trialDivisor === 0) {
                        prime = false;
                        break;
                    }
                    trialDivisor++;
                }
                if (prime) {
                    primes.push(candidate);
                }
                candidate++;
            }
            return primes.length;
        }
    </script>
</head>
<body>
    <!-- Insert your content here -->
    <form action="">
        <input type="button"
               onclick='alert(findPrimes(100000))'
               value="Find Primes" />
    </form>
</body>
</html>

Now here’s the version where we only let 1000 numbers be checked at once. After 1000 have been done, we fall out of the code, but before we go we trigger a setTimeout with a delay time of 0. That’s all we need to do to let the browser catch its breath.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title><!-- Insert your title here --></title>
<script type="text/javascript">
    function findPrimes2(topCandidate) {
        var persist=arguments.callee;
        var tries=0;
        if (persist.candidate===undefined) {
            persist.candidate=2;
            persist.primes=[];
            persist.topCandidate=topCandidate;
        }
        keepTrying = true;
        while (persist.candidate <= persist.topCandidate && keepTrying) {
            trialDivisor = 2;
            prime = true;
            while (trialDivisor * trialDivisor <= persist.candidate) {
                if (persist.candidate % trialDivisor === 0) {
                    prime = false;
                    break;
                }
                trialDivisor++;
            }
            if (prime) {
                persist.primes.push(persist.candidate);
            }
            persist.candidate++;
            tries++;
            if (tries>1000) {
                keepTrying=false;
            }
        }
        if (keepTrying) {
            persist.candidate=undefined;
            alert(persist.primes.length);
        } else {
            setTimeout(persist,0);
        }
    }
    </script>
</head>
<body>
    <!-- Insert your content here -->
    <form action="">
        <input type="button"
               onclick='findPrimes2(100000)'
               value="Find Primes" />
    </form>
</body>
</html>

Compare the two versions. In the second, I’ve short-circuited the loop so that it only checks 1000 numbers to see if they are prime. To keep comparisons easy, I’ve tried to make the least number of changes I could. In real-world cases, you start with the idea that you’re going to work in chunks, and your code ends up cleaner.

Some Are Sticky, Some Aren’t

We’ve made some of the variables persistent. These are the ones that have to be kept across invocations of the function. All other variables dry up and blow away.

Since arguments.callee is such a long name, I’ve set the variable persist to hold the current function name.

This is not a recursive function. We let the function finish. It’s set up to be called again with setTimeout. You don’t want to wait around in busy loops, making the browser all gummy and unresponsive.

If you do have responsiveness problems, put a longer delay and check fewer candidates at a time. This will make the process take longer, of course. It’s a trade-off.

Any wait longer than a couple seconds is going to make the user wonder what’s going on. A progress bar is the best solution for long waits. For short waits, a throbberis OK.

Program flow is not obvious when using setTimeout to control flow. In larger programs when you’re using this technique, you may want some kind of handler that’s in charge of passing control from one section of the code to another, instead of hardcoded setTimeout chaining.

Immediate Execution

JavaScript functions are versatile. They are powerful and flexible and exotic like a carnival contortionist. It’s amazingly easy to get into trouble with them. Not just small trouble, but big-time Pinocchio-hanging-out-with-Lampwick trouble.

Here’s a great way to get sucked into some such trouble:

var i;
for (i=0;i<5;i++) {
    setTimeout(function() {alert('The number is '+i);},
               5000);
}

I think most programmers would expect this code to give you five alerts, and that the alerts would look like this:

The number is 0
The number is 1
The number is 2
The number is 3
The number is 4

But that’s not how it works. Instead, you get this:

The number is 5
The number is 5
The number is 5
The number is 5
The number is 5

What’s happening?

The inside function (the one in the setTimeout call) is a closure. A closure has access to its parent function’s variables, even after the parent function is done. In this case, we’re setting up five alerts. This happens very fast, before the first alert has executed. So by the time the alerts happen, the loop counter is 5.

So how do you fix this?

Well, the first answer is that it’s a dumb way to do it. You can pass setTimeout a string instead of a function and solve it that way, or just call one setTimeout and have that one call the next one.

But I’ve had a problem similar to this with click handlers on a series of buttons, so let’s go ahead and look at a real solution.

for (i=0;i<5;i++) {
  (function(num) {
    setTimeout(function() {alert('second '+num);},5000);
  })(i);
}

Huh? That looks crazy. Let’s figure it out.

Here’s a function.

function lert() {
    alert("Nope");
}

Here’s another function.

(function () {
    alert("Yep");
})();

What are the differences between them?

  • The first function has a name (the name is “lert”), while the second function does not have a name.
  • The first function does not execute until it’s called, but the second function executes immediately.

To get the immediate execution, we wrap the function in parentheses and follow it with another pair of parens. That’s just how it is–get used to it.

That’s how our solution works, except it needs to be a bit fancier because we need to pass a parameter in.

Quickie: Nameless functions in arrays

In JavaScript, you can write functions that look like this:

    function add(a,b) {
        return a+b;
    }

    function multiply(a,b) {
        return a*b;
    }

It’s the C way of writing functions, so it should look pretty familiar and comfortable. But it’s really just a short cut. There’s another way to write named functions.

    add = function(a,b) {
        return a+b;
    }

    multiply = function(a,b) {
        return a*b;
    }

If we like, we can put functions into objects.

ops={add: function(a,b) {return a+b;},
     multiply: function(a,b) {return a*b;}};

and now we can call the functions ops.add(a,b) and ops.multiply(a,b). Or, you can use another notation and call the functions with ops[“add”](a,b) and ops[“multiply”](a,b);

In a similar manner, because arrays can hold objects, we can do this:

ops=[function(a,b) {return a+b;},
     function(a,b) {return a*b;}];

I’ve stripped out the names of the functions and now they look like the anonymous functions that are so common in JavaScript. In this case we still have a way to call the function–by indexing into the array. Normally we create anonymous functions on the fly and bind them to an event like like a button click and never call the function directly in our code.

To get to these almost-anonymous functions I’ve defined in the array, call ops[0](a,b) or ops[1](a,b).