Que Logo

Chapter 20

What To Do When It Won't Work: Debugging Your Scripts



In This Chapter

Bugs! Bugs! Bugs!


Whether it's ants at a picnic or cockroaches in the closet, bugs aren't most people's favorite critters. They get in things, spoil things, and generally cause a great deal of consternation. Their appearance usually gets a standard response: insecticide, a fly swatter, or a call to the exterminator. Bugs just aren't popular-unless you're a bug collector. (Any bug collectors out there, please accept my apology; I'll use the proper term: entomologist.)
Computer programs are no different from the rest of life. Programs don't always work and when they don't, it is said (in another humorous adaptation by programmers of yore), "This program has a bug." Whether it's termites in your walls or errors in your code, a bug is a bug, and a bug isn't good.
As you embark down the path to JavaScript enlightenment, you'll no doubt encounter a few bugs of your own. In the next few pages, you'll take a look at some of the more common causes of bugs and how to exterminate them.

The End Result


A bug can occur in two forms, one sometimes more insidious than the other. The first sort of bug makes itself quite obvious, like a cockroach in the middle of the kitchen. These bugs prevent the program from executing beyond a certain point due to some illegal statement. JavaScript can recognize these, and as we will discuss shortly, attempt to scold you.
The more insidious bugs, perhaps not unlike termites deep in the foundation, are those that are not illegal statements but are based on incorrect logic. Your program executes, because the statements are "legal," but the results are incorrect because your programming logic was flawed at some point. These can be extremely difficult to exterminate. We'll discuss such nasties second.

BZZT! The ERROR


When your bug is the result of an illegal statement, JavaScript will holler at you with a big pop-up alert box. To wit...

A JavaScript error message.


The first line of the error window identifies the file (or URL) where the bug occurred, while the second line tries to identify the bug. In this figure, the real problem was that a built-in JavaScript function was misspelled.. but the error states that the function (as it was misspelled) was "not defined." This is the browser's way of saying, "I can't find a function by that name," and it makes an important point: errors that you may get in JavaScript will help tell where the bug occurred, but they may not tell you exactly what the error was. Therefore, figuring out what caused an error will sometimes require a bit of sleuthing.
Another thing you might notice is that the first line ends with the word "line," and a number. This is the line number in the HTML document where the error was found, which should at least help you find its location. Note that every line of the HTML file is counted as one line-not just those containing JavaScript code. Sometimes, unfortunately, the URL is longer than the error window, and the line number isn't displayed. You can try to grab the edge of the window with the mouse to resize it, but you won't have much luck. An unfortunate error (yep, a bug) in the Netscape browser is that if the URL is very long (or even moderately long), the rest of the line identifying the specific location of the bug will be cut off. Perhaps they'll fix this in a future version.
Because illegal statement errors are often the easier bugs to rid, the previous information is half the battle, if not more. JavaScript has already told you where and in which statement the problem lies. Thus, you can spelunk into the code with some accuracy to where the bug resides. From there, your final mission (which you should choose to accept) is to determine why the noted statement is illegal. There are several possibilities you should consider, which are detailed in the following sections.

Tpyo…er…Tipo…uh…Spelling Errors


The biggest sources of bugs, by far, are typographical errors. In a word: misspelling something important. Unlike humans, who can still get the general idea of what you're trying to say (whether you remember to put the "i" before the "e" or not), computers aren't so flexible. If it isn't spelled exactly, the computer doesn't have a clue what you mean. The problem with "typos," as they're called, is that (as you saw in the previous section) the browser isn't smart enough to say, "Ahh, you didn't spell it right." If it were, the browser would know what the right value was… right?
Instead, a typo can cause one of several things to happen:
And the list goes on… and on… and on. In a nutshell, spelling something wrong is a lot like trying to order in a French bistro when you don't speak French: depending on what word you get wrong, you could end up with anything from a scoop of sorbet to a boiled shoe. Check your spelling!

A Capital Idea


"Kissin' cousins" to spelling errors are errors in capitalization. The JavaScript documentation notes that JavaScript is case-sensitive (upper- and lowercase matter). Case is important, and capitalization is critical.
Many functions, methods, and properties in JavaScript are "compound words" made up of more than one word slapped together (for example, getDate()). In most cases, the second word is capitalized while the first word is not. If you try to type in a JavaScript component and don't capitalize the second (or third, or fourth) word, you'll probably generate an error.
The Appendix, "JavaScript: The Complete Reference," which lists all the components of JavaScript-and Chapters 6 through 14-show the proper capitalization for JavaScript functions, objects, and properties.

Matching Mates


There are many occasions in JavaScript programming when you use paired bookends, such as brackets { }, parentheses ( ), and both single- and double-quotation marks.
As with socks in the laundry, improperly matching pairs will result in a statement of problematic fashion. It is vital that every open bracket and parenthesis have an appropriate closing mate somewhere further down in the code. Where people most often lose track is when they are nesting parentheses or brackets, such as when using a loop statement within a loop statement.
It is not uncommon to find multiple closing parentheses or brackets at the end of a series of statements, which pair up with a series of opening mates earlier on. It might look strange, but an eye for an eye and a bracket for a bracket, as they say (don't they?). Something to watch for.

JavaScript Errors


If you're still stumped and you're positive you spelled everything correctly, then move to Phase 2: interpreting the JavaScript error message. JavaScript has a handful of errors that it kicks up for a variety of situations. Take a look at each and what to check for if you encounter one. For purposes of the "error lineup," look at the second line of text displayed in the error window. Any parts of the message that may change will be represented by a string of question marks (?????).

????? Is Not Defined


You've already met this guy. He's trying to tell you that either you misspelled something or have forgotten to include the function body (the guts of the function) in the script. It might also mean that the function requires an uppercase letter or two, so you might want to check the function against what you find here in the book.

????? Is Not a Function


You tried to call an object's function (for example, document.write()) and the function doesn't exist. Check the spelling and capitalization.

????? Is Not a Numeric Literal


You attempted to perform some sort of math operation on a string. For example, if you wanted to take the numeric value 2 and display on the screen 2nd, trying something like:

document.write(2 + "nd");

will generate this error. This is because, as JavaScript evaluates the expression inside the parentheses, the type of the expression is whatever variable type JavaScript encounters first when reading from left to right (or whatever way is the default for evaluation_using more than one pair of parentheses can change this order). In this example, JavaScript assumes that you want to print out a numeric value, but then you try to tack a string on the end (a no-no).
To get around this, you need to "convert" the expression to a string before you start evaluating it. You can easily do this by adding a "null" or "empty" string in front of the number:

document.write("" + 2 + "nd");

The Dreaded "Crash"


Sometimes, things get really hairy and you're presented with the infamous "illegal operation" dialog box.

Something's seriously wrong!


 
Netscape itself shuts down. First rule: don't panic. Chances are you've done something simple that, while the browser should have a better way of handling it, blindly charges forward until it gets hopelessly stuck.
A common way to cause this error (if you really like creating bugs instead of fixing them) is to try to treat a numeric value like a string and manipulate it. For example:

var n = 264;
document.write(n.substring(0, 1));

will definitely cause a crash. However, if you convert the number to a string first:

var n = 264;
var strN = "" + n;
document.write(strN.substring(0, 1));

then everything's fine.
Along the same lines, calling a method of a numeric variable (even if it's not a string method) will also cause Netscape to explode. There isn't any "solution" other than the punchline to that old joke: don't do it. Actually, the fault isn't yours, it is Netscape's--it should generate an error in such circumstances, not crash. Presumably, future revisions to Netscape will weed out these landmines.

Design Errors (or Why Did My House ;
Just Collapse?")


Often sneakier and much more difficult to track down are outcome bugs. These are not the result of an illegal statement that JavaScript cannot understand. They are the result of errors in program design, which produce the wrong results when you execute the program.
Think of an entire JavaScript program (or any computer program, for that matter) as a large exercise in logic and grammar. Even if your grammar is impeccable (JavaScript makes no error complaints), your logic may be flawed. It may be flawed in one tiny section of code, several tiny sections of code, or perhaps your entire design is logically flawed.
Ultimately, the only solution to these problems requires three possible steps:
  1. Locate the region of code likely to contain the design flaw.
  2. Follow the logic and redesign where necessary.
  3. Return to step 1 if the problem persists.

Finding the Holes Where the Rain Gets In


Suppose you've written a JavaScript program that calculates a loan payment schedule. The program contains no syntax errors, but the alleged payment amount it reports is clearly incorrect. You have a design flaw (don't feel too down; virtually every program contains some design flaw the first time around).
To locate the region of code where the flaw is most likely, you have to consider the program itself. Presumably, you have several functions in such a program, each of which performs some calculation. Therefore, any of those would make good suspects at this point, since a wrong final tally is probably caused by an erroneous calculation.
Look at the sections of code you might suspect. Read them over carefully and follow the logic in your mind. Should no flaw be immediately apparent, then dip into the programmer's toolbox for handy debugging tool number one: the inside scooper.
One of the most revealing ways to track down design bugs is to gain some insight into what is going on "behind the scenes" while the program executes. A very common way to do this is to stick new lines of code here and there that display the current values of particular variables. This way, when you execute the program again, you have a better idea of what is going on "in there." In JavaScript, I commonly do this using the window.alert() method. For example, let's imagine that my suspect code looks like this:

function evalform (address)
{ crucial = address.indexOf("@") ;
 if (crucial == -1) 
 { window.alert ("Your e-mail address is invalid! You are an abject 
_liar!") ;
 return false }
 else
 { message = "You entered " + address + " - is this correct?";
 return window.confirm (message) } ;
 }

To check behind the scenes, I might like to find out just what JavaScript thinks the values of address and crucial are. Thus, I could stick the following two lines just after the second line above:

window.alert ("Value of address is "+address);
window.alert ("Value of crucial is "+crucial);

Now, when the program is executed again, the values for those variables will be displayed, giving you some clue as to whether they are at least what you were expecting them to be or not. If they aren't, then you must begin your investigation again, but at least you've narrowed it down (do remember, though, to remove these lines of code once the program is working, since they're not intended to be part of the final program).
In addition to variable values, another common test is for program flow. Did the execution even reach your function? Perhaps your function was never even executed due to some other design flaw in your logic. You can test for this simply, just like before: stick a line somewhere within the questionable function that you're sure will generate some action if the function is, in fact, being executed. Perhaps, window.alert ("Hi function bob was just called"), for instance.

Sigh and Rebuild


Using some combination of the previous example-perhaps many times, if necessary-you will eventually track down the region of code that is logically flawed.
From there, you must determine the flaw and rebuild. The only sure way to determine the flaw, once you're certain you have the right portion of code, is to step through it mentally, bit by bit. In a Zen-like way, imagine that you are the computer, and attempt to interpret the code exactly as the computer would. Perhaps grab a pencil and paper and write down the values of variables as you progress through your mental exercise. This can be very tough work. Sometimes, the logic flaw will pop out to you quickly. In a most difficult case, you might be stumped. This is the "art" of programming.
Clear heads help, so time away from the screen can be of use. Equally useful are smart people, or at least experienced ones, and so there are many places on the Internet where people exchange programming hints and pose questions to others. Check out the Usenet newsgroup comp.lang.javascript for just such chatter-and support.

The Least You Need To Know


Bugs are a common problem when you're creating programs, and working with JavaScript is no exception. JavaScript tries to provide information on where the bug is and what it is, but it isn't the most accurate analysis of the problem. Furthermore, a particular bug can generate an error that makes no sense whatsoever_unless you understand a few tricks.
For the most part, mistakes in spelling or capitalization are the worst culprits when it comes to bugs. The three questions you, as a JavaScripter, should ask are:
If your code is free from grammatical errors, it might be suffering from design flaw. You need to examine the logic of your code.

Previous Chapter

Next Chapter


Beginning of ChapterTable of ContentsBook Home PageQue Home Page


For comments or technical support for our books and software, select Talk to Us.
To order books, call us at 800-716-0044 or 317-228-4366.

© 1996, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon & Schuster Company.