Tutorial 13 - Getting the bugs out

Tutorial 12 - Smart Forms - Tutorial 14 - Regular Expressions

Bugs or programming errors occur often when learning a new programming language or when developing a new routine or utility. Ripped or cut/pasted scripts are often filled with latent bugs as well. This tutorial will hopefully give you some successful strategies for squashing any bugs that occur in your JavaScript writings or trying to get ripped scripts to work correctly.

Types of JavaScript Errors

There are several types of error, each with its own method of detection and repair. The basic types of error are:

Browser Implementation Errors
These are quirks that occur in one browser but not others. See Browser Issues for more details. Test your code on all anticipated client browsers!
Syntax Errors
These are errors in grammar and punctuation such as mismatched quotes or missed commas. These errors are caught quickly if you have the browser's built-in error detector in display mode or run the script through JS Lint.
Runtime Errors
These errors only show up as the script is executed. Common examples are calling a function that hasn't been declared (typing error or case-sensitivity issue) or division by zero. Although JavaScript is typeless, many built in objects expect and/or return specific types (eg. style.left needs string type).
Logic Errors
These are basic errors in the programmer's algorithms or procedural errors. Diagnosis only comes when incorrect results occur and solution requires mapping out the flow for test cases. The wrong scoping of a variable is an example of this kind of error.
Incorrect Operator Precedence Errors
These are basic mathematical grouping errors. The best way to avoid them is with brackets to force the order that you want operations to occur explicitly.

Using Your Browser's Debugger

Microsoft Internet Explorer has a built-in debugger but you must first enable it by selecting Tools -- Internet Options -- Advanced. Uncheck the box labeled 'disable script debugging' and check the box that says 'display a notice about every script error'. Note: MSIE 5 users will have to first download the debugger utility from Microsoft. Note that the line number given in any error message is only approximately correct ;-]

Netscape 7 and Mozilla Group browsers have a current version of the Venkman browser that is accessible from the Tools menu option. Netscape 6 users must download Venkman from Mozilla Projects. The Venkman tutorial is a comprehensive document for learning how to use this important debugging tool

Netscape 4 users must enter javascript: in the location bar to obtain an error report. Any error will be listed along with the correct line number. Some messages are very cryptic but at least you know where to start looking ;-] .

Alert Windows and the Status Line

Previous tutorials have shown how to use the alert window to provide feedback to the user. This same technique can be used by a JavaScript programmer to set breakpoints (ie pauses) and watch the value of variables within the code. Don't forget to use the typeof() operator to check the type of the variable. And sometimes it is more convenient to use window.status to display variable contents without pausing the program.

Using write() and writeln() Methods

At times you may want to analyze a list of values. You can open a new window and use the write() or writeln() methods. This is the equivalent to the use of print or printf statements in other languages.

Using the JSlint Validator

JSlint is an on-line validator that is very easy to use. Simply cut and paste your script into the text entry zone and press the JSlint button. Any error will generate a simple text message and a line number reference. This is an excellent way of getting the lint out of the wash ;-]

JSlint enforces a style that is tighter than what most browsers need but which detects many common mistakes that programmers make. Some of the guidelines are as follows:

  • jslint expects that every statement be followed by ; except for for, function, if, switch, try, and while.
  • jslint does not expect to see unnecessary semicolons or the empty statement.
  • jslint does not expect to see an identifier, a string, a number, or a suffix operator such as ) ] ++ -- at the end of a line.
  • jslint expects that if and for statements will be made with blocks {that is, with statements enclosed in braces}.
  • jslint expects blocks with function, if, switch, while, for, do, and try statements and nowhere else.
  • jslint expects that a var will be declared only once, and that it will be declared before it is used.

Common JavaScript Errors

Errors can take some of the fun out of programming but experience will gradually eliminate (or at least make you more watchful for) certain commonly made ones. Some of the most common errors are:

  • Spelling and typo errors. Remember case sensitivity and avoid hard to find lookalikes (1 and l, 0 and O, etc.).
  • Not matching brackets or quotes correctly.
  • Wrong type of bracket. Each has its own use.
  • Not using the escaper backslash when required.
  • The type of the variable may be critical in spite of being a typeless language.
  • The scope of a variable can affect its current value.

Browser Issues

In the nineties, browsers developed at a fast pace and without standards. This led to proprietary ways of doing things and the need for sniffing to see what browser was being used. But in today's world there is a known recommendation for both script [ECMA] and DOM [w3.org]. Unfortunately some recommendations are vague and consequently are implemented differently. Also texts and on-line material continue to use legacy methods which no longer work in the modern browsers. The next few subtopics are a guide as to what to beware in texts, tutorials and ripped scripts. The best way to avoid problems is to stick with the ECMA/w3.org recommendations!

Netscape 4

Netscape originally used a layers model for DHTML. Netscape 4 introduced a layer element which could be manipulated or positioned with effects similar to what developed later with the div element in the DOM model. However the manner in which this was programmed was very different than that chosen for the DOM method. Because of both technical and political considerations, w3.org chose to recommend using only the DOM model.
As an example of layers style document.flyer.left or document.layers['flyer'].left was the Netscape 4 equivalent to document.getElementById("flyer").style.left.

If you are required to support Netscape 4, you must first sniff for it and set a global variable appropriately. Then at any point where DHTML is used, set up a branch that uses either DOM or the layers model as needed. CSS1 technote may help those who are supporting Netscape 4. As it is so very old now, I choose not to support it! You can move Netscape 4 users off a page by using a transfer method, detect and raise an alert message, or just neglect them altogether.

Microsoft Internet Explorer

MSIE has properties in addition to those in the DOM model. But it is better to find these and replace with w3.org recommendation coding. For example both pixelTop and pixelLeft can be replaced by top and left.

where=styleObj.pixelLeft;  //MSIE specific
where=parseInt(styleObj.left); // makes integer count in pixels
. . .
styleObj.pixelLeft=where;  // MSIE specific
styleObj.left=where + 'px' // guarantees measured in pixels

document.all is MSIE specific. It should be replaced with the DOM construct document.getElementById('ident').

For some reason MSIE does not like smart forms to be nested in definition lists even though it is a valid html construct. This can result in SELECT box text becoming inaccessible.

JavaScript variable names that are the same as html ids can cause error messages within MSIE. This is an undocumented enhancement in MicroSpeak. ;-] ;-]

MSIE has filters and transitions which look slick but only in MSIE. Avoid the use of any proprietary feature! It is just not worth the maintenance hassle.

An example of a vague recommendation in DOM that causes a problem in MSIE is the sequence of actions when both focus and blur (anti-focus) occur at the same time. Here is a fragment that tries to insure that a field is not empty as soon as you move to the next field. Unfortunately, in MSIE it leads to an endless loop.

<script type="text/javascript">
function requiredString (control, label) {
if (control.value.length == 0)
   {alert("you need to enter a string for "+label); control.focus();}
}</script>
. . .
<input name="Control1" onBlur="requiredString (this, 'Label1');">
<input name="Control2" onBlur="requiredString (this, 'Label2');">

Browser Sniffing

The document object model (DOM) is a convenient way of understanding how to access html elements. Unfortunately the major browser makers have chosen to implement the DOM objects differently. And older browsers used a concept called layers to achieve many of the effects now done with the DOM model. Thus there are compatibility problems that must be overcome either by programming branches within a script, offering different pages depending on browsers, defensive programming, warning users of possible conflicts, or benign neglect (playing the percentages that one browser has over 90 percent of the users). It is important to realize that there is an issue! Decide how you will deal with these differences. And know your clients, their browsers, and their ability to upgrade to newer, better ones! Browser sniffing is commonly used:

  • to invoke either DOM or layers depending on the browser's age
  • to program around various vendor interpretations of what the style object should be
  • to avoid problems with tags that certain browsers do not handle well
  • to provide an alternate stylesheet for a specific browser

Sniffers can be designed to either return a single value denoting the appropriate browser and version or to set global variables which flag capabilities such as DOMable, layered, etc.

One strategy that allows for maintainability and documentation is to identify the object properties that are different and build a JavaScript module of functions to deal with the variations. This isolates the selection of processing techniques to one area of your script. Further scripts allow reuse of the functions and if a newer browser requires sniffer tweaking, it is only needed in one file.

The first example identifies a browser as a non-dom model and transfers to a page that works ok using layers. This can also be used to skip a page eg a fancy splash screen) entirely if that is the author's method of dealing with variations.

var dom=document.getElementById; //browser uses DOM ??
if (dom==0) {top.location.href="http://www.xyz.com/nextpage.htm"}

Variations on this theme is to check for layer users (eg Netscape 4) or MSIE specific browsers.

if (document.layers) {ns=1} else {ns=0}
if (document.all) {ie=1} else {ie=0}

The next example is of an older style sniffer that relies on the basic navigator object properties available even in the older browsers. In many cases identifying the browser by name and version is sufficient. But BEWARE! Many browsers have the capabilities of identifying as another browser (aka spoofing).

/* Note: sniffer must id older Netscape browsers */
ie=0; ns=0; gecko=0; opera=0;
agent=navigator.userAgent;
browser=navigator.appName;
version=parseInt(navigator.appVersion);
agent=agent.toLowerCase();
browser=browser.charAt(0);
if (agent.indexOf('gecko') != -1) {gecko=1;}
if (agent.indexOf('opera') != -1) {opera=1;}
if (browser=="N" && version < 5) {ns=1;} else {ie=1;}

Important Note: The above example is provided only for historical purposes and to indicate what you should avoid! Modern techniques use feature identification for sniffing.

Tutorial 12 - Smart Forms - Tutorial 14 - Regular Expressions

Copyright (c) 2005 by John W. M. Russell