File Under: JavaScript, Programming

Advanced JavaScript Tutorial – Lesson 5

Wow – you made it to the last and final lesson! Stunning. As a reward for all your hard work, I’ve made this lesson extremely relaxing – no nitty-gritty code to wrap your mind around and no hairy homework, just coding theory and pointers to resources.

The topics for the day are:

  • Tools to help you write JavaScript
  • Debugging techniques
  • Tips for making your JavaScript code run quickly


Contents

  1. Tools of the Trade
  2. Debugging Techniques
  3. Printing Variables
  4. Common Programming Mistakes
  5. Fixing Bugs
  6. Good Coding Practices
  7. Optimizing Your JavaScript for Speed
  8. What’s Next?

Tools of the Trade

To tell the truth, I don’t use anything other than a word processor to write JavaScript. Call me old-school – crusty even. Though plenty of tools out there write JavaScript for you, the code they generate is pretty obtuse and difficult to change. If you really want to use a tool to create JavaScript, I suggest Dreamweaver, which pumps out some amazing JavaScripts in very little time. However, if you ever want to tweak the scripts later, be prepared to look at some awfully ungainly code.

You can also find tools that help you debug JavaScript. I don’t use these either. Netscape has one, and so does Microsoft, but I’ve never met anyone who’s successfully used these debuggers. Go ahead, prove me wrong. But until someone convinces me that a product is worth buying (hint, hint, hint – send me that free software), I prefer to debug the old-fashioned way.

Debugging Techniques

As you program JavaScript more and more, you’ll begin to understand those opaque error messages JavaScript gives you. And once you understand the common errors of your ways, you’ll soon know what pitfalls to avoid, and the raw code you generate will be less and less error-prone. Programming is definitely a skill that improves dramatically over time. But no matter how skilled you become, you’re still going to spend some time debugging.

If you’ve been doing your homework, or have ever tried writing JavaScripts of your own, you know that a considerable hunk of your scripting time is spent debugging. This is normal – it’s just one of those things programmers have to do. In fact, according to numerous studies, 50 percent of the average programmer’s time is spent figuring out what’s wrong with code.

The key is to learn how to debug your programs efficiently. I have several tips to help you figure out why your program isn’t doing what it should, or to avoid writing buggy code in the first place:

  • Print out variables in various ways
  • Watch for common mistakes
  • Think before coding


Let’s start with printing those variables.

Printing Variables

Once you find a bug, you can get rid of it. Unfortunately, finding the suckers isn’t always easy – most of your debugging time is spent just figuring out the location of the error.

One of the most tried-and-true debugging methods is to put simple statements in your code that print out what’s going on. Let’s say you’re having a problem with these two functions:

 function getName()

 {

    var first_name = prompt("what's your first name?","");

    var last_name = prompt("what's your last name?","");

    var the_name = first_name + " " + last_name;

 }



 function theGreeting()

 {

    var the_name = "";

    the_name = getName();



    if (the_name == "Dave Thau")

    {

 	alert("Hello, oh greatest one!");

    } else {

 	alert("Ahoy palloi!");

    }

 }

Give this example a try and see if you can figure out what’s wrong (Netscape 3.x users may experience some error check problems due to the nature of this, and the following Javascript examples). If you enter random names into the alert boxes, you get the greeting “Ahoy palloi!” However, if you enter “Dave” in the first prompt box and “Thau” in the second, you’re supposed to get the message “Hello, oh greatest one!” Instead, you still get the “Ahoy palloi!” message. Obviously, something’s wrong with the functions. In this simple example, you could probably find the errors just by looking at the JavaScript. However, as your scripts get more and more complicated, finding your errors just by eyeballing them grows increasingly difficult.

If JavaScript doesn’t catch your error, and you can’t figure it out just by looking at your script, it sometimes helps to print out variables. The easiest way to do this is with an alert(), like this:

 // theGreeting gets a name using getName, then presents one or two

 // alert boxes depending on what the name is

 //



 function getName()

 {

    var first_name = prompt("what's your first name?","");

    var last_name = prompt("what's your last name?","");

    var the_name = first_name + " " + last_name;

    alert("in getName, the_name is: " + the_name);

 }



 // theGreeting gets a name using getName, then presents

 // one of two alert boxes depending on what the name is

 //



 function theGreeting()

 {

    var the_name = "";

    the_name = getName();



    alert("after getName, the_name = " + the_name);



    if (the_name == "Dave Thau")

    {

 	alert("hello, oh greatest one!");

    } else {

 	alert("ahoy palloi!");

    }

 }

Notice we’ve placed alerts at all the important points. Now try the version with lots of alert boxes. If you enter the names “Dave” and “Thau,” you’ll notice that the first alert says “in getName, the_name is: Dave Thau,” but the second alert says “after getName, the_name = undefined,” which tells you things got messed up right after the last line of getName(). Somehow, the_name is OK just before the function exits, but theGreeting doesn’t correctly set the variable the_name. When you’ve written a function that does the right thing, but has problems returning a value, the first thing you should check is whether you’re actually returning the value. And sure enough, that’s the problem here. The getName() function figures out the name, but never returns it. So we need to add return the_name; at the end of the function.

Putting a bunch of alert boxes in your code is very helpful. Unfortunately, hitting “OK” every other line is also sort of a pain.

You can do a few things to debug your code without the hassle of the alert box. One option is to write your debugging messages to a text area inside a form. Another possibility is to write the debugging messages to another window. Here’s an example of debugging code that writes debugging messages.

A third trick that can make your debugging experience more pleasant involves creating different debugging levels and then setting a “debug” variable. Here’s the JavaScript that actually runs on this page:

 // debug can be either none, alert, or textarea depending

 // on the kind of debugging I want to do

 //

 var debug = "none";



 // function getName gets a first and last name, concatenates

 // them with a space in between, and returns the name

 //

 function getName()

 {

    var first_name = prompt("what's your first name?","");

    var last_name = prompt("what's your last name?","");

    var the_name = first_name + " " + last_name;



    var error_message = "in getName, the_name is: " + the_name;

    doError("in getName, the_name is: " + the_name);

 }



 // theGreeting gets a name using getName, then presents

 // one of two alert boxes depending on what the name is

 //

 function theGreeting()

 {

    var the_name = "";

    the_name = getName();



    doError("after getName, the_name = " + the_name);



    if (the_name == "Dave Thau")

    {

 	alert("hello, oh greatest one!");

    } else {

 	alert("ahoy palloi!");

    }

 }





 // doError is the error handling routine

 // depending on the type of debug message

 // it presents either no debug message, an alert

 // or puts the message in a textarea

 //

 function doError(the_message)

 {

    if (debug == "alert")

    {

 	alert(the_message);

    } else if (debug == "textarea") {

 	window.document.the_form.the_text.value += the_message + "<br>n";

    }

 }

 

Notice that I’ve defined a variable called “debug” that can be either “none,” “alert,” or “textarea.” Then when I want to generate an error message, I send it to the function doError(), which either does nothing, presents an alert box with the message, or sticks the message in a text area, depending on how I set the debug variable. You can set the debug variable to “textarea,” when you have lots of errors that you want to look at simultaneously. Then, when you’re ready to show your code to the world, you can just set debug to “none,” and the error message will no longer show up, which saves you the hassle of having to find and remove all your debug statements.

Often, programmers create different debug levels, such as “none,” “brief,” and “extreme.” “Brief” will print a few debug messages along the way, “extreme” will print a lot of debugging messages, and “none” will of course print no messages.

If you build your debugging system like this, you can set the debug level to “brief” while you’re coding, and “none” when you’re ready to make your JavaScript public. Then, if something totally weird starts happening, and you don’t know where to look for the problem, you can set the debug level to “extreme” and wade through all the debug messages until you find something suspicious.

OK, enough about debugging systems. Let’s turn now to common mistakes made by JavaScript coders.

Common Programming Mistakes

Most mistakes are just silly syntactic ones. It takes a long time to remember to close all those quotes, curly braces, and parentheses, but luckily the automatic JavaScript bug detector catches most of those errors for you. Though JavaScript bug detectors keep improving as browsers get more sophisticated, a few bugs still slip through the cracks. Here are a few common ones to look out for:

Messing up variable or function names.
Mistakes with capitalization and pluralization of variable and function names are annoyingly typical and sometimes the JavaScript bug detector fails to catch them. By creating and adhering to a naming convention for your variables and functions, you can greatly reduce the number of these mixups. For instance, I name my variables in all lower case and with underscores in the place of spaces ( my_variable, the_date, an_example_variable), and I use in-fix notation for my functions ( addThreeNumbers(), writeError(), etc.). I avoid pluralizing anything because I always forget which variables are plural and which variables aren’t.
Accidentally using reserved words.
Some words can’t be used as variables because they’re already in use by JavaScript. For example, you can’t have a variable named “if” because it’s actually a part of JavaScript – if you use “if,” you’ll wreak all kinds of havoc. While you’d have to be pretty deranged to name a variable “if,” a variable called “document” may be more tempting. Unfortunately, “document” is a JavaScript object. Another often used, but generally problematic thing to call a variable is “name” (form elements have “names”). Naming a variable “name” doesn’t always cause problems, only sometimes, which can be even more confusing – all the more reason to avoid calling a variable “name.” Unfortunately, different browsers have different reserved words, so there’s no way to know exactly which words to eschew. The safest course of action is to avoid words that are part of JavaScript as well as those found in HTML. If you’re having problems with a variable and you can’t figure out what’s wrong, try renaming the variable. If that works, then you’ve probably stumbled across a reserved word.
Remembering that you need two equals signs in logical tests.
Some browsers catch this error, and some don’t. This is a very common mistake and extremely difficult to catch if the browser doesn’t point it out for you. Here’s an example of the error:
 var the_name = prompt("what's your name?", "");

 if (the_name = "the monkey")

 {

 	alert("hello monkey!");

 } else {

 	alert("hello stranger.");

 }

This code will throw up the “hello monkey!” alert box regardless of what you type into the prompt, which isn’t what we want. That’s because there’s only one equals sign in the if-then statement, which tells JavaScript that you want to set one thing equal to another thing. Let’s say you type “robbie the robot” into the prompt. Initially, the_name will be “robbie the robot.” But then the if statement tells JavaScript that you want to set the_name = “the monkey.” So JavaScript happily follows your command, and sends a “true” message to the if-then statement, and the alert box shows up with the “hello monkey!” message every time. This insidious bug can drive you belfry batty. So concentrate on doubling those equals signs.

Accidentally quoting variables, or forgetting to quote strings.
This one gets me time and time again. The only way JavaScript knows the difference between a variable and a string is that strings have quotes around them and variables don’t. Here’s an obvious error:
 var the_name = 'koko the gorilla';

 alert("the_name is very happy");

This will produce an alert box that says “the_name is very happy,” even though the_name is a variable. This is because once JavaScript sees quotes around something, it stops thinking about it, so by putting the_name in quotes, you stop JavaScript from looking it up in its memory. Here’s a less obvious extension of this bug (which we saw in Day 3):

 function wakeMeIn3()

 {

 	var the_message = "Wake up!  Hey!  Hey!  WAKE UP!!!!";

 	setTimeout("alert(the_message);", 3000);

 }

  

The problem here is that you’re telling JavaScript to execute alert(the_message) in three seconds. Three seconds from now, however, the_message no longer exists because you’ve exited the function. The solution to this problem is this:

 function wakeMeIn3()

 {

 	var the_message = "Wake up!";

 	setTimeout("alert('" + the_message+ "');", 3000);

 }

 

By pulling the_message out of the quotes like this, the command "alert('Wake up!');" is scheduled by the setTimeout, which is what you want.

These are just some of the harder-to-debug errors that might sneak into your code. Once you’ve found your bugs, there are good and bad ways to go about fixing them. Lucky for you, I can give you the benefit of my trials and errors.

Fixing Bugs

Finding a bug, though sometimes difficult, is only the first step. Next you have to get rid of it. Here are a few things you should do as you crush those bugs:

Copy your program first.
Some bugs are really hard to get rid of. In fact, sometimes a little bug can drive you so crazy that, in the process of eradicating it, you destroy your entire program. Saving your program before you start debugging is the best way to ensure that a bug doesn’t get the best of you.
Fix one bug at a time.
If you know about several bugs, fix each one and test your fix before you move on to the next bug. Fixing a lot of bugs all at once without checking your work is just an invitation for even more bugs.
Beware of voodoo coding.
Sometimes you know a bug exists, but you don’t really know why. Lets say you have a variable called “index,” and for some reason “index” is always one less than you think it should be. You can do one of two things: sit there for a while and figure out why it’s coming up short or just shrug, add one to index before using it, and move on. The latter method is called voodoo programming. When you start thinking “What the hell – why is index two instead of three? Well … I’ll just make it work for now and fix it later,” you’re slapping a Band-Aid on a potentially serious wound. Voodoo programming may work in the short term, but you’re looking at long-term doom – if you don’t understand your code enough to really get rid of a bug, that bug will come back to haunt you. It will either return in the form of yet another weird error that you can’t figure out, or it’ll make your code extremely hard to understand for the next poor soul cursed to look at it.
Look for similar bugs.
In some ways, the ability to cut and paste code is the worst thing for programmers. Often, you’ll write some JavaScript in one function and then cut and paste it into another function. And if the first function had a problem, you now have problems in two functions. I’m not saying you shouldn’t cut and paste code. But bugs have a way of multiplying, so if you find one, you should look for others that are similar. (Or just make sure something works before you start creating multiple versions of it.) Misspelled variable names are the kind of thing that crops up several times in one JavaScript – misspell the_name as teh_name in one place, chances are you’ve done it someplace else.
If all else fails …
If you’re sitting there, staring at a bug, and you just can’t figure out what’s going on (or if you can’t even find the bug in the first place, but you know it’s there because your program isn’t working right), the best thing to do is walk away from your computer. Go read a book, take a stroll around the corner, get a tasty beverage – do something, anything, but don’t think about the program or the problem. This technique is called “incubation” in some circles, and it works amazingly well. After you’ve had a little break and relaxed, try finding the bug again. You’ll approach the problem with a refreshed vision that’s often quite illuminating. Incubation works because it breaks you out of a (dare I say it?) dysfunctional mindset. If you follow a wrong path for too long, you sometimes get stuck with no room in which to turn around. The best thing to do when this happens is find a way to start down a new path. I know it’s touchy-feely, but it works. Really!
And if that doesn’t work …
Ask someone for help. Sometimes you wear such a rut in your problem with repetitious thought patterns, only someone with a fresh eye can see the hole in your logic. In structured coding environments, programmers periodically review one another’s code. This is appropriately named “code review,” and it not only helps iron out bugs, it also results in better code. Don’t be afraid to show other people your JavaScripts. It makes you a better JavaScripter.
But the absolute best way to eradicate bugs is …
to create bug-free code from the get-go.

Good Coding Practices

The key to good programming is to write programs for people, not computers. If you keep in mind that someone else will probably read your JavaScript, you’ll write much clearer code. The clearer your code, the less likely you are to make mistakes. Clever coding is cute, but it’s the clever coder that gets the bug. The best rule of thumb is KISS, Keep It Simple, Sweetie.

Another helpful technique is to comment before you start writing any code. This forces you to think about the problem before diving right on into it. Once you’ve written the comments, you can write the code right below each one. Here’s an example of a function written this way.

Step 1: Write the comments


 //function beSassy()

 //  beSassy asks for a user's name, chooses a random

 //  insult and returns an alert box with the user's

 //  name and the insult.

 function beSassy()

 {

 	//  first write a list of insults

 	//



 	//  next get the user's name

 	//



 	//  then choose a random insult

 	//



 	//  finally, return the personalized sass

 	//

 }



'''Step 2: Fill in the code'''





 //function beSassy()

 //  beSassy asks for a user's name, chooses a random

 //  insult and returns an alert box with the user's

 //  name and the insult.

 function beSassy()

 {

 	//  first write a list of insults

 	//

 	var the_insult_list = new Array;

 	the_insult_list[0] = "your shoe lace is untied";

 	the_insult_list[1] = "your mama!";

 	the_insult_list[2] = "it's hard to be insulting";



 	//  next get the user's name

 	//

 	var the_name = prompt("What's your name?", "");



 	//  then choose a random insult

 	//

 	var the_number =  Math.random() * 5;

 	var insult_number = parseInt(the_number);

 	var the_insult = the_insult_list[insult_number];



 	//  finally, return the personalized sass

 	//

 	alert("Hey " + the_name + " " + the_insult);

 }

This comment-first policy not only forces you to think before you code, it also makes the task of coding seem a lot easier – by breaking things down into little, easily coded sections, your problem looks less like Everest and more like a bunch of pleasant rolling hills.

And finally …

Always end your statements with semicolons.
Although it’s not strictly necessary, you should get into the habit of ending all your statements with a semicolon since it clears the way for code to come. Forget that semicolon, and suddenly the next line of perfectly good code generates an error.
Initialize your variables with “var” unless you have a good reason not to.
Localizing all your variables using “var” reduces the chance that one function will mess up the workings of another, unrelated function.

OK, now that you know how to code, let’s learn how to make your JavaScript run quickly.

Optimizing Your JavaScript for Speed

Once you’ve gotten your JavaScript working, you might want to get it working faster. Before I go into the ways to speed up your code, let me bend your ear about something called the 80/20 rule. You get 80 percent of the improvement of optimization with the first 20 percent of the work you do. Eking out that remaining 20 percent of speed is a huge pain, and often results in completely unreadable and difficult-to-manage code. In short, if your JavaScript is running slowly, there are a few very simple things you can do to speed it up, but unless your script is still really slow, I wouldn’t bother optimizing beyond that.

Here are a few easy methods of getting the lead out of your code.

Limit the amount of work you do inside loops.

The most common cause of a really slow program is repeated work inside a loop. If a command only needs to execute once, there’s no reason to put it in a loop. For example:

 var index = 0;

 while (index <10)

 {

    var the_date = new Date();

    var the_day = the_date.getDay();

    var the_name = prompt("what's the kid's name? " ,"");

    alert("On " + the_day + " " + the_name + " is a very special person.");

    index++;

 }

This program loops 10 times. Each time it figures out what day it is, asks for a kid’s name, and then prints out “On Monday, so-and-so is a very special person.”

But the day never changes. It’s always today. So there’s no need to put the first two lines inside the loop. Rather than execute them 10 times, pull them out of the loop and save time by executing them only once:

 var index = 0;

 var the_date = new Date();

 var the_day = the_date.getDay();

 while (index <10)

 {

    var the_name = prompt("what's the kid's name? " ,"");

    alert("On " + the_day + " " + the_name + " is a very special person.");

    index++;

 }

 

Order if-then-else statements from most likely to least likely.

Because if-then-else statements end once they’ve found something true, you can reduce the number of statements that execute by putting the ones most likely to be true first. For example:

 var pet = prompt("what kind of pet do you have?", "");

 if (pet  == "cat")

 {

 	doCatStuff();

 } else if (pet == "dog")

 {

 	doDogStuff();

 } else if (pet == "bird")

 {

 	doBirdStuff();

 } else if (pet == "lizard")

 {

 	doLizardStuff();

 }

 

On average, this list of if clauses will execute fewer logical tests than if it went from lizard to dog.

Minimize repeated expressions.

If you find yourself repeatedly calculating a specific expression, like var pi = 22/7, it’s probably a good idea to just calculate it once and access it as a global variable. For example, instead of this:

 function theArea(radius)

 {

 	var pi = 22/7;

 	var area = pi * radius * radius;

 	return area;

 }



 function theCircumference(radius)

 {

 	var pi = 22/7;

 	var circumference = 2 * pi * radius;

 	return circumference;

 }

 

do this

 var pi = 22/7;

 function theArea(radius)

 {

 	var area = pi * radius * radius;

 	return area;

 }



 function theCircumference(radius)

 {

 	var circumference = 2 * pi * radius;

 	return circumference;

 }

Yeah, I know that I’m using a global variable here, and I said that it was a bad idea. However, numbers like pi, which will never change during your program, are the exception to this rule. By calculating pi only once, you save an extra calculation. A small savings in time, perhaps, but it all adds up. These are just a few things you should look for if your code is too slow. They’re pretty obvious, but you’d be surprised how often you can overlook simple optimizations like these.

And that, my friends, brings us to the end of today’s lesson, which in turn brings the entire Advanced JavaScript tutorial to a close. And if you’ve come this far, and you’ve read even half of the last five lessons, you’ve seen a lot of JavaScript. In fact, if you’ve understood most of what I’ve covered in the 10 lessons that span Parts I and II, you can safely call yourself a JavaScript acolyte. The road to true mastery now lies only with practice.

What’s Next?

Now that you have a working understanding of JavaScript, you can write some pretty serious JavaScripts. It’s time to move on to some of JavaScript’s many applications. Add dynamic HTML to your skill set, and you’ll be ready to achieve your wildest dreams. Well some of them anyway.

But above all, you need to practice, practice, practice. Swipe existing code and mangle it beyond all recognition. Write scripts from the blank page up. Strive to create bug-free code, and become a master at fixing the bugs that slip through anyway. Keep your eyes peeled for interesting and new applications of JavaScript, and figure out how they’re done. It doesn’t even matter if your code works perfectly or not, because it all teaches you something. The more you learn, the better – and faster – your code becomes and the easier it is for you to create it.

Now go forth young JavaScripter, and do me proud!

Thau!