So far, you've learned the basics of JavaScript and several advanced techniques. You have explored several examples, all of which were tested and debugged for publication in this book.
At this point, you're probably interested in creating your own unique JavaScript applications, and you may have run into some problems. In this chapter, you'll explore some common errors and misconceptions in JavaScript programming.
You'll also look at some tools and techniques you can use to debug your programs. Finally, you'll explore some problems that aren't your fault-bugs in various implementations of JavaScript. You'll also consider the impact of these bugs and explore ways of working around them.
Although JavaScript is one of the simplest programming languages, there are still some statements, functions, and techniques that can be confusing. You will explore some of the most common errors you might make, and their symptoms, in the next sections.
Some of the most common errors you might make in a JavaScript program are syntax errors-errors in the punctuation, object names, and such that make up a program.
Some syntax errors are obvious. For example, you might miss a comma or period, or spell the name of an object wrong. Netscape recognizes most of these errors and will point them out to you.
Unfortunately, some of the easiest syntax errors to make can be the hardest to detect. Netscape won't detect them, and the program may even work-but produce the wrong result. You'll explore the most difficult syntax errors in the following sections.
One of the most common errors people make in JavaScript is to confuse the assignment (=) operator with the equality (==) operator. This can often be one of the hardest errors to spot in your source code. If you've done any programming in C or Perl, you'll recognize this as one of the most common errors in those languages also.
Luckily, JavaScript is able to detect this error better than most languages. For example, the following line of JavaScript code mistakenly uses the assignment operator:
if (a = 5) window.status="a is 5";
When the JavaScript interpreter encounters this line, it recognizes that it was probably intended as an equality test and gives you an error message indicating this (see Figure 14.1). The interpretation of the program continues and treats the line as if it were an equality test. (Of course, you should still fix it.)
Figure 14.1 : Netscape recognizes when you have used an assignment operator by mistake.
If you make the opposite mistake-using == when you should have used =-the error message isn't quite as clear. In fact, you may not receive an error message. For example, this program will generate an error message:
a == 5; if (a == 5) window.status="a is 5";
The first statement is considered an error because you are trying to compare the variable a with a value, but a currently has no value. The error message produced by this example is shown in Figure 14.2.
Figure 14.2 : the error message produced when you used the equality error by mistake.
However, consider the following modified version of the example:
a = 7; a == 5; if (a == 5) window.status="a is 5";
In this example, the variable a has been defined and assigned a value, before the equality operator is used. This makes a == 5 an expression that simply evaluates to true, doing nothing. No error message is produced, but the correct action is not performed.
Another common error in JavaScript is to leave out some details of an object's name-for example, in the following form definition:
<FORM name="form1"> <INPUT TYPE="text" NAME="text1"> </FORM>
If you want to access the value of the text1 text field, the correct syntax is this:
document.form1.text1.value
It's often tempting to refer to the object as simply text1, but it won't work without the document and form name. If the previous form was defined in a different frame, you would also need to refer to the proper frame:
parent.frames[1].document.form1.text1.value
Obviously, things can get complicated, especially when you're working with multiple documents, windows, and frames. If you have used the incorrect name, you will usually get the same error message: name has no properties. Figure 14.3 shows an example of the error message when the form name has been left out.
Figure 14.3 : The error message you usually get when using the incorrect name for an object.
A few common errors involve punctuation. These usually result in an error message when the page is first loaded, and include the following:
You should also keep close watch on your capitalization, because JavaScript variable, method, function, object, and property names are case-sensitive. For example, this statement is invalid because the random() method should not be capitalized:
a = Math.Random();
Tip |
If JavaScript gives you an error message saying that a name is invalid, doesn't exist, or has no properties, look for a punctuation or capitalization error. |
Because a JavaScript program is embedded within an HTML document, errors in the actual HTML can affect your program. HTML is a complicated language in itself, and this book can't cover all of it here; however, here are some common HTML errors that can affect JavaScript programs:
Some of the objects and properties in JavaScript can be confusing. The best example of this is that the document and the window both have a location property. These are very different things:
A common error is to attempt to set document.location to send the user to a new URL. This doesn't generate an error message, but also doesn't accomplish anything. You should always use window.location.href to load a new URL.
Another area of confusion is the history object. Some references, such as Netscape's own documentation, refer to the history object as a property of document. However, it is actually a property of the window object. Each window has its own history.
For example, to go back to the previous document, you should use
the window.history.back()
method, or simply history.go().
To go back to the previous document in the frame1
frame, you would use parent.frame1.history.back().
Using document.back() results
in an error.
Note |
You can omit the window keyword if you are referring to an object (such as history) in the current window. If you are referring to a different window, you need to use its name. You cannot omit the document keyword. |
A number of potential JavaScript programming errors are caused by failure to understand various timing factors-the order in which a document loads and JavaScript code executes. Here are some examples of problems of this nature:
Sometimes variables can create problems. One of the most confusing aspects of JavaScript is the scope of variables-in other words, where a variable can be used. As you have learned, there are basically two variable scopes in JavaScript:
Problems can occur when you cut and paste JavaScript routines
between two pages. You might be using a global variable for one
routine with the same name as a local variable used in another
routine. Any time a variable's value changes unexpectedly, suspect
this type of problem.
Note |
Two different local variables (local to two different functions) can have the same name without causing a problem. |
JavaScript has a list of reserved words-words that you can't use as variable names because they serve an important purpose within JavaScript. Because this list includes all the object properties in the object hierarchy, it can be quite long.
This can create problems if you choose a name that matches a reserved word. For example, suppose you created an order form that includes a name, address, and phone number. You might choose the obvious names name, address, and phone for those text fields. However, because form.name is a predefined property that holds the name of the form, this can create conflicts.
In some cases, the property might not work the way you expect
it to, or change value unexpectedly, because the internal JavaScript
property has priority. In other cases, your new property might
override the built-in property, causing a different set of problems.
Tip |
Refer to appendix B for a complete list of JavaScript reserved words. |
JavaScript is designed as a platform-independent language. In other words, the Windows, Macintosh, and UNIX versions of Netscape should run a script in exactly the same way.
For the majority of JavaScript features, this is true; however, there are still a few differences in the way JavaScript works on the different platforms. Here are a few common platform-specific problems:
There are many other minor differences between platforms. Worse, when the current version of Netscape is a beta version, there may be different bugs for different platforms, or the version may not be available for a particular platform yet.
How do you keep up? The differences are usually minor, so you
can usually avoid these issues. Because most of us don't have
several computers handy to test a program on every platform, the
best you can do is put it on the Web-you'll get feedback from
users if there's a problem.
Tip |
If you use much JavaScript in your pages and change it frequently, you may wish to find at least one user on each platform to use as a beta tester. Send that user a note when you change your pages, to make sure the user works on all platforms. |
Let's look at two techniques you can use in the process of debugging your JavaScript programs. Either of these methods can be used to test the value of a variable at intermittent points and follow the data through the program.
The simplest way of adding debugging information to a JavaScript program is to use the window.alert() method to display a value. For example, the following section of code includes an alert to test the value of the text variable:
text = document.form1.text1.value; window.alert("Value:" + text);
Remember that because JavaScript is a loosely typed language, you can include numeric variables, string variables, and floating-point variables in the alert text. Here's an example:
a = 5.66; b = 2; window.alert("a is " + a + " and b is " + b);
In the process of debugging a JavaScript program, you might add
statements like this several times to find the cause of a problem.
After determining the problem, you can remove the alert
statement.
Tip |
You can also use the status line to view debugging information. However, the value you display there might be erased by Netscape or by your program. |
For larger-scale debugging needs, you can open a new window and use it to display debugging information. The following is an example of a statement to create a new window called bug to display debug information in:
bug = window.open("","bug","status=0 toolbar=0");
After opening the debug window, you can use a simple function to write data to it:
function debug(text) { bug.document.writeln(text); }
You can now use the debug() function to display debug messages in the new window. Listing 14.1 shows a detailed example of this technique, and Figure 14.4 shows the output in the debug window.
Figure 14.4 : Using a temporary window to display debugging information.
Listing 14.1. (TEMPWIN.htm) A simple program that displays debug information in a temporary window.
<HTML> <HEAD><TITLE>Test of Debugging Window</TITLE> <SCRIPT> //open the debug window bug = window.open("","bug","status=0 toolbar=0 height=100 width=400"); bug.document.write("<HTML><HEAD><TITLE>debug</TITLE></HEAD>"); bug.document.write("<BODY><h1>debug output</h1><hr><PRE>"); //function to write to debug window function debug(text) { bug.document.writeln(text); } a = 17.5; b = 29; c = "This is text"; debug("Value of a is: " + a); debug("Value of b is: " + b); debug("Value of c is: " + c); </SCRIPT> </HEAD> <BODY> <h1>Test of Debugging Window</h1> <hr> this is a test. </BODY> </HTML>
If you've programmed with C, Perl, or another full-scale programming language, you might be used to the benefits of a complete debugger, which enables you to step through programs, test variables, and perform other helpful tasks automatically.
JavaScript is a simple language and is not equipped with a debugger. However, you're not entirely alone in your task of debugging a JavaScript program. You will learn about two tools in the next sections that can help:
Although you won't find any mention of it in Netscape's documentation, there is a debugging tool of sorts built into Netscape Navigator (all versions that support JavaScript). It has no official name, but it's called the JavaScript command line here.
To access this tool, simply type javascript: in Netscape's Location field and press Enter. If you're a slow typist or enjoy coffee-related terms, you can type mocha: to access the same screen. The resulting screen is divided into two frames horizontally; the top one is blank, and the bottom frame includes a text field. The initial JavaScript command line screen is shown in Figure 14.5.
Figure 14.5 : The JavaScript command line: a simple debugging tool.
As you might guess, the JavaScript command line enables you to type a command into the blank. When you press Enter, the command is executed. The top frame is used to display the status of each of the commands in a scrolling list.
Although this won't help you debug an existing program, it can be very useful in the process of learning JavaScript or planning a project. You can test commands in this command line to find out easily how they work and what they return.
As an example, Figure 14.6 demonstrates the use of the command line to test the window.confirm() method. I have already tried it several times, and you can see the result (true or false) for each trial. The confirmation dialog is currently displayed along with the command that produced it.
You don't have to use an actual statement in the command line. You can use any valid JavaScript expression. The result of evaluating the expression is shown in the upper frame. For example, Figure 14.7 shows the result of several trials of the Math.random() method.
Figure 14.7 : The result of several trials of the Math.random() method using the command line.
When you're working at the command line, you can use variables and even create functions. The only restriction is that anything you do has to fit in the text field. For example, you could define a simple function to add 5 to a number by typing this command:
function add5(num) {return num+5}
Once you've done that, you can type this expression:
add5(39)
and the result (44) will be displayed.
Tip |
You can also use the JavaScript command line as a convenient calculator. Type an expression, such as 5*30, and it will be evaluated. You can even define variables and use them in your calculations. |
You can also skip a step and enter a JavaScript command directly into Netscape's Location field. Use javascript: (or mocha:) as the method before the command. For example, you can type the following into the Location field to display an alert message:
javascript:window.alert("This is an alert.");
This makes it easy to test a statement or expression quickly.
Using this method, however, you cannot define functions or perform
other complex operations.
Tip |
You can also use javascript: as a link destination to make links that execute a JavaScript statement or function. This is an alternative to event handlers. You saw some uses for this technique in Chapter 12. |
Obviously, the JavaScript command line leaves something to be desired as a debugger. It enables you to test statements, but it doesn't do much good in testing complete applications. The JavaScript Trace Facility is a third-party utility that allows a wide variety of options for testing a program.
The JavaScript Trace Facility was created by Fred Highland ([email protected]). It is copyrighted, but it can be copied for use in your own JavaScript programs.
To use the Trace Facility, you need to copy its functions into the HTML file with your script. You can also use the <SCRIPT SRC=> tag in later versions of Netscape to include it in your file.
To copy the Trace Facility functions, load the page at this URL:
http://www.fred.net/wwmfarm/javastra.htm
Tip |
The JavaScript Trace Facility is also included on the CD-ROM accompanying this book. |
Once you've done this, you can use the functions for interactive debugging and tracing.
The Trace Facility includes several functions that you can use for debugging and tracing. The first, trace_form(), creates a form to hold the results of the trace. In the call to this function, specify the width and length of the form. This example:
trace_form(60,5)
defines a form with 5 lines, 60 characters across.
The JavaScript Trace Facility debug form is shown in Figure 14.8. It includes the following components:
Along with the debug form, the JavaScript Trace Facility includes a variety of functions that you can use to track events in your program. The output of each of these commands appears in the Trace Output window of the debug form:
Caution |
All these trace functions will slow down your program, and they should be used only while debugging. The statistical functions are particularly time-consuming, and they may not work well with complex programs. |
JavaScript is continually being developed and improved; because of this, you should always use the latest version of Netscape to test and debug your JavaScript applications. However, you're probably making your applications available to users all over the world via the Web, and there's no way to ensure that they have all upgraded.
In the next sections, you'll look at each of the versions of Netscape
and Microsoft Internet Explorer that support JavaScript, their
limitations and bugs. If users report a problem with your script,
you should refer to this list to determine whether the problem
is caused by their browsers.
Note |
Bugs in JavaScript are still being fixed-and still being discovered. There is no way to guarantee that every possible bug is included, but I have tried to include all known problems at the time of this writing. |
Tip |
For more detailed information about each version of Netscape, including versions released after this book, refer to Netscape's release notes at this URL: http://home.netscape.com/eng/mozilla/3.0/relnotes/index.html. |
JavaScript was introduced in version 2.0 of Netscape Navigator. There were several beta versions of version 2.0 before the final version, and JavaScript progressed in these versions. You'll look at some of the problems in the beta versions, then in the released version.
You will also look at some memory problems in JavaScript in this section. These are not described by Netscape in the release notes, but have been discovered by users (usually causing a crash). You'll also look at some ways of avoiding the problem.
JavaScript was introduced in the first beta release of Netscape Navigator 2.0. It was originally called LiveScript, and the <SCRIPT> tag used "livescript" as its language value. It was also available only for the Windows platforms.
In version 2.0 beta 2, support was added for Macintosh and UNIX platforms. Improvements continued until version 2.0b6, the last beta release.
Several bugs are present in the beta versions. Here are some of the most important ones:
Although the final release of Netscape 2.0 is a much more stable product than any of the previous versions, it still has several JavaScript-related bugs and limitations:
Along with these problems, Netscape 2.0 suffers from some memory leaks when JavaScript is used. This means that certain JavaScript code can use up memory, often resulting in an out-of-memory error or crash.
The most common cause of this problem is when you repeatedly assign
a value to a string. JavaScript cannot modify the value of a string
without re-creating the entire string. If you change a string's
value repeatedly in a loop, memory will quickly disappear.
Tip |
Some of the worst cases of memory leakage occur in scrolling-message programs, which assign a new value to a string every second or faster. The scrolling message program introduced in Chapter 8 "Improving a Web Page with JavaScript," avoids this problem. |
Netscape Navigator 2.01 did not add any new features (or bugs) to JavaScript. It did remove several features for security reasons, however. These include the following:
This is an incremental release that fixed a number of bugs in version 2.01. The main bug was a problem with Daylight Savings Time, which caused pages to remain in the cache even when they had been changed. There were also some minor fixes to JavaScript:
At this writing, Netscape Navigator 3.0 is under development and several beta versions have been released. Some of these versions were released under the code name "Atlas." Many new features have been added in these versions.
Netscape 3.0 added many new features to JavaScript. In fact, many of the features you already learned about were added in this version. JavaScript didn't really "grow up" until version 3.0 was released. Here is a summary of the new features:
Unfortunately, several bugs still plague the beta versions of Netscape 3.0. These should be fixed in a later release. These include the following:
At this writing, Microsoft has begun to support JavaScript with an early alpha version of its Web browser, Microsoft Internet Explorer (MSIE) 3.0. At present, this support is very minimal.
Currently, few of the examples in this book will work in MSIE
3.0 at all, and many will cause a crash. My recommendation is
not to attempt to support this browser until it is more finished;
Microsoft has promised full JavaScript support in the final version
of MSIE 3.0.
Tip |
You'll take a closer look at MSIE, ActiveX, and VBScript in Chapter 18, "Using ActiveX and Microsoft Internet Explorer 3.0." |
In this chapter, you explored some of the many ways JavaScript programs can fail, and what to do about them:
You should now have a good understanding of the techniques you can use to debug even the most stubborn JavaScript program. Now move on with one of the following:
Are all the causes for Netscape crashes covered in this chapter? | |
By no means. I've tried to cover the most common causes, but there are still occasional crashes-in any program, not just Netscape-that can't be explained. Watch also for new bugs in any future version. | |
What's the easiest way to avoid the problems with hiding JavaScript from older browsers with HTML comments? | |
Instead of using comments, use the <SCRIPT SRC> command and store the script in a separate file. This feature is supported in Netscape 3.0b5 and later versions. | |
If the onLoad event doesn't necessarily happen after the document is finished loading, how can I be sure it's finished? | |
A simple workaround is to set a timeout in the onLoad handler to execute your function a few seconds later. Netscape has promised a method to verify this in a future version. |