Debugging JavaScript programs

A quick reference guide to finding errors without the aid of a debugging utility

Everyone makes mistakes writing JavaScript programs. Errors don't know experts from novices, so the next time you get an error message while trying to play a JavaScript program you've written, don't feel bad. JavaScript provides error messages as a means to help you spot mistakes. This column describes the errors you are likely to get when writing a JavaScript program and what to do about them.

They say that novels are not written, but rewritten. Certainly the same goes for computer programs, including those written in JavaScript. Bugs are the bane of any programmer, and debugging is part of the program development process.

Unfortunately, client-side JavaScript currently (circa 1996 -- ed.) lacks a debugging utility, so finding errors in your script becomes a lesson in deductive reasoning. You cannot -- as yet, anyway -- set a breakpoint and have your browser display the contents of registers or variables if a program terminates unexpectedly.

Tools for debugging JavaScript

This classic JavaWorld article, written in 1996, presents time-tested tips for understanding the nature of JavaScript bugs and working them out simply and strategically. See "Ajax: Tools of the trade" (Nate Schutta, 2009) and "JavaScript tools for the HTML5 generation" (Peter Wayner, 2012) to learn about tools that can help you write and debug modern JavaScript programs.

Debugging a JavaScript program entails using problem-solving techniques that would impress Sherlock Holmes. Effective debugging of JavaScript requires some experience writing programs for it. After a while, you become familiar with the error messages JavaScript displays and learn ways to solve the errors. Of course, you may not have the time to devote yourself to learning all the intricacies of JavaScript. This column is your quick-reference guide to understanding how to effectively debug JavaScript programs, even without a debugging utility.

Determining the type of error

There are three general types of errors that can occur when playing a JavaScript program. These errors are:

  • Load-time errors
  • Runtime errors
  • Logic errors

Load-time errors are those that are caught by JavaScript as Navigator loads the script. These errors are the major mistakes that prevent the script from functioning before it has a chance to start. It is during the loading process that JavaScript spots any serious errors that will cause your script to fail right off the bat. The script cannot be run until the page has been successfully loaded.

Load-time errors are perhaps the most common and are generally caused by problems in syntax. To help you determine the problem, JavaScript displays a warning box when a load-time error occurs. The warning box tells you the problem and, most of the time, shows you the actual text of the error. Bear in mind that the warning box doesn't always indicate the actual error. Depending on the problem, the error may be located at a different part of the line or even on another line.

As an example, general errors in syntax, such as forgetting to provide the proper open and close braces around a function, create a load-time error. Here's one such example (the actual error message is "missing } after function body"):

function test () {
    alert ("hello")

Even if your script loads without a peep, there is no guarantee that it will run smoothly. Runtime errors are those that occur when the script is actually playing. As with load-time errors, runtime errors are displayed in an alert box. The nature of the error is specified, along with a line number (which isn't always accurate), so you can hunt down the error in the same document.

Where load-time errors are generally caused by mistakes in syntax, runtime errors are most often due to improper use of commands. For instance, you will receive a runtime error if you reference a variable that hasn't been defined. The following results in a runtime error.

Messsage = "This is a test";    // note three s's
document.write(Message);    // note two s's

Another type of runtime error occurs when you misapply one of JavaScript's objects. For example, this code fragment results in an error ("document cannot be set by assignment.") because you cannot assign a value directly to the document object.

document="test";

Finally, a logic error is when your script does something different than that suggested by logic. The error isn't due to a misplaced parenthesis or misapplied statement, but rather to a mistake in the way you've constructed the script. For example, a logic error occurs if you fail to anticipate the user entering invalid data. The script may fail because the data it processes is not in the proper format.

Common causes of errors

You'll find that most of the errors that beset your scripts are caused by the same, and rather simple, mistakes. Make sure you look for the following:

  • Proper variable names. Keep a sharp eye out for the variables you use and their names. Avoid giving two variables similar names, such as MyVar and MyVal. Avoid one-character differences in variable names, such as Name and Names. And, of course, be sure that the variables you use are spelled properly throughout the script. Remember: JavaScript variables are case sensitive. MyVar is not the same as myvar.
  • Proper function names. Be sure function names are spelled correctly and that they don't have any extraneous characters or spaces.
  • Unique function names. Function names can be used only once in a script (of course you can call a function any number of times). Review all functions to make sure that you haven't duplicated their names.
  • Commas for arguments. With the exception of the for statement (following C and Java practice), JavaScript uses the comma as the separator character for arguments.
  • Proper placement of braces. JavaScript uses the { and } brace characters to define a block of statements. Be sure to include all the necessary brace characters for the statement block or errors will result.
  • Quotes around strings. All strings should have quotes around them.
  • Proper script sequence. It's possible to enter a statement into a script at the wrong place while editing it, especially if you're using time-saving, cut-and-paste techniques. Double check.
  • Correct object names. Be sure names for objects are spelled exactly, and with the proper capitalization. Remember that the built-in objects (Date, Math, Array, Object, etc.) have initial caps; the others start with lowercase letters. Develop a consistent naming convention for your variables, objects, and functions.

Determining the source of a problem

An important step in repairing a broken script is isolating its various functions and routines, and analyzing it on a piece-by-piece basis. This can be done using a number of low-tech approaches, such as setting watchpoints using alert message boxes, and taking advantage of the for/in statement to peer into JavaScript's objects.

More from JavaWorld

Want more programming tutorials and news? Get the JavaWorld Enterprise Java newsletter delivered to your inbox.

Setting watchpoints

Many logic errors are caused by incorrect values in variables. One way to help you spot these logic errors is to set "watchpoints" at one or more spots in the script. These watchpoints are alert boxes that display the contents of the variables. You can also use alert boxes to determine if your code is reaching a certain point in the program. (I use something like alert("to here") to verify the code is working.) Remove the alert watchpoints after the script has been debugged.

Type single-line command entry in the Location box

A little-known JavaScript testing shortcut is to type a JavaScript command line in Navigator's Location box. Preface the command line with the JavaScript: protocol, like that shown below, and press the Enter key to see the result:

javascript:alert ("this is a test")

Note that not all command lines provide meaningful results. For example, typing

javascript:document.write ("this is a test")

and pressing Enter results in true printed in the document window.

If you need to test a number of command lines, you can reduce the keystrokes by typing javascript: (remember the colon) in the Location box. Navigator displays a "JavaScript typein" frame at the bottom of the window. Type the command line you want to try, and press Enter.

Type multiple-line commands using a helper script

The "JavaScript typein" frame window described above is defined within Navigator. You can create your own version of it to allow for simplistic multiple-line command entry (this script is very basic and can be improved, but it serves to get you going). The following displays a multiline JavaScript typein utility. The multiline command entry script is a combination frameset and JavaScript-generated frame document. To use, type the script segment you want to test in the text-area box, and choose Run.

Note: When using this script be sure to append semi-colons (;) at the end of each line. This helps JavaScript properly parse the command lines you enter.

<SCRIPT>
function jsinput () {
parent.MochaInput.document.write ("<b>JavaScript input</b>")
parent.MochaInput.document.write ("<form action=JavaScript: target=MochaOutput>")
parent.MochaInput.document.write ("<textarea name='isindex' rows=5 cols=50>")
parent.MochaInput.document.write ("</textarea><BR>")
parent.MochaInput.document.write ("<input type='submit' value='Run'>")
parent.MochaInput.document.write ("</form>")
}
</SCRIPT>
<FRAMESET ROWS="50%%,50%%">
<FRAME NAME="MochaOutput" SRC="about:blank">
<FRAME NAME="MochaInput" SRC="javascript:parent.jsinput()">
</FRAMESET>

Make paper copies

JavaScript programs are composed of text embedded in HTML documents. Therefore, you can use any text editor program that has a print capability to make paper copies of your scripts. The paper copies may help you find errors that are otherwise hidden in screenfuls of code displayed on your monitor.

You may find it helpful to print your JavaScript programs in a monospaced font, such as Courier, to help spot such mistakes as a string that is empty but should contain a space. The monospace font is better suited to locating these kinds of errors, but it does takes up more space on the line. Use a small 9- or 10-point font to compensate.

Use a simple object inspector

The for/in statement can be used to create a simple object inspector. A short script is all you need to inspect a JavaScript object. For example, to get a listing of the current properties of the window object, load the script and type window in the prompt box. Choose OK. JavaScript displays an alert box listing each property of the window object.

<SCRIPT>
ret = prompt ("Enter object", "document");
obj = eval(ret);
var temp = "";
for (x in obj)
    temp += x + ": " + obj[x] + "\n";
alert (temp);
</SCRIPT>

Six mistakes everyone makes

Here are a half-dozen of the most common mistakes people make when writing JavaScript programs. These are listed in no particular order.

1. Missing quotation marks for strings

This should go without saying, but I'll say it anyway: Remember to provide quotes (either single or double) for all strings. The obvious use -- and most common site of abuse -- is the document.write method.

document.write(<H1>This is a heading</H1>);

This will cause a load-time error when the browser tries to load the script, because quotes are missing within the document.write statement. JavaScript doesn't know quite what's wrong here; it just tells you there's a syntax error and leaves it to you to figure out what's wrong. Add quotes to fix.

2. Mismatching quotation marks

JavaScript lets you use the single quote (') or the double-quote (") to delineate strings. However, you must be careful to stick with the same type, or else JavaScript will render an error message. The following is not allowed, because the characters used for the quote symbol are not consistent.

document.write("<H1>This is a heading</H1>');

JavaScript lets you "embed" a quoted string within another. In this case, you will want to use both quote types. However, keep in mind that for every type of quote that starts the string, you must have a matching end quote. Here's an example. Notice that the entire string is enclosed in single quotes, and the "internal" string is enclosed in double quotes. The result is a heading that appears as Ways to "Improve" Your JavaScript Programs.

document.write('<H1>Ways to "Improve" Your JavaScript Programs</H1>');

3. Using single equals instead of double equals in comparison expressions

This mistake is so common (unless you're a dyed-in-the-wool C programmer) you're bound to do it at least once. JavaScript expects to see two equals signs in a comparison expression, not one. This is a mistake:

if(MyVar = "xyz")

4. Referencing objects that don't yet exist

Navigator processes a page in the order it receives its HTML markup. It is common to place JavaScript code at the beginning of the page (usually in the <HEAD> tag). This can lead to errors if you attempt to reference some other part of the page that hasn't been loaded. For example, the following JavaScript attempts to reference a form control when the page is loaded. This reference comes before the control has been defined, so an error occurs.

<SCRIPT>
document.write ("Hello<P>");
document.test.box.value = "Hello again";
</SCRIPT>
<FORM NAME="test">
<INPUT TYPE="text" NAME="box">
</FORM>

5. Using the wrong object hierarchy with forms

A common problem is referring to a form as a property of a window. This results in a confusing error -- "formname has no properties" (formname is the name of the form). It's confusing because the form is obviously an object with properties. For example, the following JavaScript says "test has no properties," yet it's obvious the test form is a valid object with properties:

<FORM NAME="test">
<INPUT TYPE="text" NAME="box">
</FORM>
<SCRIPT>
window.test.box.value = "Hello";
</SCRIPT>

The fix is to reference the form as a document property, as in:

document.test.box.value = "Hello";

6. Using string methods with objects that don't support those methods

Some of JavaScript's objects return values that look like strings, but they are not true strings. For instance, the following displays the name of the current document URL. Although the return value looks like a string, it is not, and therefore doesn't support any string object methods or properties, such as indexOf or toUpperCase.

var ret = location;
alert (ret.toUpperCase());  // results in an error

You need to convert the return value to a true string, then use the string methods/properties with the converted value. The toString method offers one general approach you can often use:

var ret = location.toString();
alert (ret.toUpperCase());  // no error this time

JavaScript error messages

Here is a list of the more common error messages you are likely to encounter when working with JavaScript. The messages are listed in alphabetical order in two sections: load-time errors (errors that occur when a script is loaded into the browser) and runtime errors (errors that occur when you play a script).

Load-time error messages

These error messages appear when an HTML document containing JavaScript is first loaded.

function does not always return a value

JavaScript found one or more return statements in a function that returned a value, and at least one return statement that didn't return anything. For example, the following script will result in an error in JavaScript:

function myBadFunction (val)  {
    if (val==0)
    return;
else
    return ("some text")
}

To fix this error, make sure all of the return statements are the same. All should return either something or nothing.

identifier is a reserved word

You tried to name a variable or object with a word that is reserved by JavaScript. Some words are reserved because they are used by JavaScript as names for statements, functions, methods, or objects. Other words are reserved for future use. These words are not currently used by JavaScript, but may be used some day. For example, the word int is reserved for future use. Using int as the name of a variable results in the "identifier is a reserved word" error:

int = "this is a test";

missing ( ... missing ) ...

These errors (the ... denotes additional error message text) occur when you've forgotten to add the appropriate opening or closing parenthesis in your JavaScript code. For example, the error "missing ) after for-loop control" occurs with the following:

for (Count=1; Count<100; Count++ {

missing ; after for-loop condition

missing ; after for-loop initializer

The for statement is missing one or more semicolons (;) to separate its arguments. This error typically occurs when you've used commas instead of semicolons -- a common mistake because JavaScript uses commas as an argument separator for everything but the for loop (the syntax of the JavaScript for loop comes from C). As an example, this results in an error:

for (Count, Count<10, Count++) {

missing { before function body / missing } after function body / missing } in compound statement

These errors occur when you forget to add the requisite brace either for a function or part of a compound statement (with, if, for, for/in, while). For instance, in the following you need a } to close out the for loop.

for (Count=1; Count<10; Count++) {
    var varOne=1;
    var varTwo=2;

nested comment

JavaScript doesn't like you to nest /* multi-line comments. The following results in an error. To fix the error remove the second /*.

/* this is a test /* of a nested comment*/

out of memory

This error message says JavaScript is out of memory and cannot perform any more actions. It typically occurs in scripts that create lots of string objects. A common example is the scrolling "marquee" used to move a train of characters across the screen or status bar. The better-written marquees shouldn't exhibit short-term "out of memory" problems, but because of code-cleanup bugs in JavaScript, continued use of the script will eventually lead to a memory failure.

syntax error

This is JavaScript's generic error message. It appears if JavaScript detects a syntax problem with the script but cannot determine precisely what it is, usually because the code leaves JavaScript in an unknown state. For example, an incomplete assignment such as the following triggers the "syntax error" message:

ThisResultsInAnError=;

test for equality (==) mistyped as assignment (=)? Assuming equality test

JavaScript uses double equals signs when testing for equality, such as in an if or while expression. This error occurs if you use only one equals sign. Fix the problem by adding a second equals sign. Here is a before-and-after example:

if (color="blue")        // not accepted
if (color=="blue")  // accepted

unterminated string literal

This is a common problem, caused when you forget to append a " or ' character to end a string literal:

NameOfMyCat="Santana

Fix the error by adding a " (or ', as needed) quote to complete the string literal. This error also occurs if the string you've defined in your script is too long (over 254 characters, when using Navigator 2.0). To fix this error you'll need to break up the string into smaller chunks, and assemble it in this manner:

MyString = "first part ";
MyString += "second part ";
MyString += "third part";

and so forth. Each separate string assignment should be 254 characters or less. There is virtually no limit (except for available memory) to the overall length of the string you define in this way.

Runtime error messages

In the following error messages, xyz denotes variable text that JavaScript provides, such as a function or variable name. These errors occur at runtime -- that is, after the script has been loaded and code is executed.

Note: The xyz identifier may not always appear in the error message. For example, instead of saying "myObject cannot be indexed as an array," the error message may simply say, "cannot be indexed as an array." Fortunately, JavaScript does provide the number of the approximate line that contains the error, which can help in tracking down the source of a problem.

xyz cannot be indexed as an array

Only objects can be indexed as an array, and this error typically occurs when you attempt to use a non-object as an array (the error also occurs if you attempt to use an array not supported by a given object, such as document.elements[0]). The following results in an error because window.length is a property, and not an object.

alert (window.length[0]);

However, the following does work because a number of properties are contained in the document object. The array index values access each of the available properties.

alert (document[0]);

xyz has no properties

The object you've referenced has no properties. This is a common error, and is usually the result of misusing objects. This error will crop up, for example, with the following:

document.history.go(1);

The error occurs because history is a property of a window, not a document. The correct syntax is:

window.history.go(1)

xyz is not defined

This error occurs when your JavaScript code references a variable or object that does not exist. For example, you get the error with the following. (Note that the assigned variable is Test, whereas the variable used with the alert method is Text.)

var Test="This is a test;
alert (Text);

Another common mistake is to use the wrong capitalization when referring to variables and objects. This code results in an error, even though you have spelled the variable name correctly:

var Test="This is a test;
alert (test);

Conclusion

Debugging JavaScript programs may not be state-of-the-art (yet, anyway). Nevertheless, with a bit of sleuthing, and a handful of simple tools and techniques, you can debug most any JavaScript coding problem you may encounter. And as you might expect, the process gets easier as you become more experienced at programming in JavaScript.

Gordon McComb is an author, consultant, and lecturer. He has written 50 books and more than a thousand magazine articles during his 20 years as a professional writer. More than a million copies of his books are in print. Gordon also writes a weekly syndicated newspaper column on computers, reaching several million readers worldwide. Gordon's latest book is The JavaScript Sourcebook, forthcoming from Wiley Computer Publishing.
Join the discussion
Be the first to comment on this article. Our Commenting Policies