BUY THIS BOOK
Add to Cart

PDF $27.99

Safari Books Online

What is this?

Looking to Reprint or License this content?


JavaScript & DHTML Cookbook
JavaScript & DHTML Cookbook Solutions and Example for Web Programmers

By Danny Goodman

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Strings
A string is one of the fundamental building blocks of data that JavaScript works with. Any script that touches URLs or user entries in form text boxes works with strings. Most document object model properties are string values. Data that you read or write to a browser cookie is a string. Strings are everywhere!
The core JavaScript language has a repertoire of the common string manipulation properties and methods that you find in most programming languages. You can tear apart a string character by character if you like, change the case of all letters in the string, or work with subsections of a string. Most scriptable browsers now in circulation also benefit from the power of regular expressions, which greatly simplify numerous string manipulation tasks—once you surmount a fairly steep learning curve.
Your scripts will commonly be handed values that are already string data types. For instance, if you need to inspect the text that a user has entered into a form's text box, the value property of that text box object returns a value already typed as a string. All properties and methods of any string object are immediately available for your scripts to operate on that text box value.
If you need to create a string, you have a couple of ways to accomplish it. The simplest way is to simply assign a quoted string of characters to a variable (or object property):
var myString = "Fluffy is a pretty cat.";
Quotes around a JavaScript string can be either single or double quotes, but each pair must be of the same type. Therefore, both of the following statements are acceptable:
var myString = "Fluffy is a pretty cat.";
var myString = 'Fluffy is a pretty cat.';
But the following mismatched pair is illegal and throws a script error:
var myString = "Fluffy is a pretty cat.';
Having the two sets of quote symbols is handy when you need to embed one string within another. The following
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introduction
A string is one of the fundamental building blocks of data that JavaScript works with. Any script that touches URLs or user entries in form text boxes works with strings. Most document object model properties are string values. Data that you read or write to a browser cookie is a string. Strings are everywhere!
The core JavaScript language has a repertoire of the common string manipulation properties and methods that you find in most programming languages. You can tear apart a string character by character if you like, change the case of all letters in the string, or work with subsections of a string. Most scriptable browsers now in circulation also benefit from the power of regular expressions, which greatly simplify numerous string manipulation tasks—once you surmount a fairly steep learning curve.
Your scripts will commonly be handed values that are already string data types. For instance, if you need to inspect the text that a user has entered into a form's text box, the value property of that text box object returns a value already typed as a string. All properties and methods of any string object are immediately available for your scripts to operate on that text box value.
If you need to create a string, you have a couple of ways to accomplish it. The simplest way is to simply assign a quoted string of characters to a variable (or object property):
var myString = "Fluffy is a pretty cat.";
Quotes around a JavaScript string can be either single or double quotes, but each pair must be of the same type. Therefore, both of the following statements are acceptable:
var myString = "Fluffy is a pretty cat.";
var myString = 'Fluffy is a pretty cat.';
But the following mismatched pair is illegal and throws a script error:
var myString = "Fluffy is a pretty cat.';
Having the two sets of quote symbols is handy when you need to embed one string within another. The following
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Concatenating (Joining) Strings
NN 2, IE 3
You want to join together two strings or accumulate one long string from numerous sequential pieces.
Within a single statement, use the plus (+) operator to concatenate multiple string values:
var longString = "One piece " + "plus one more piece.";
To accumulate a string value across multiple statements, use the add-by-value (+=) operator:
var result = "";
result += "My name is " + document.myForm.myName.value;
result += " and my age is " + document.myForm.myAge.value;
The add-by-value operator is fully backward-compatible and is more compact than the less elegant approach:
result = result + "My name is " + document.myForm.myName.value;
You can use multiple concatenation operators within a single statement as needed to assemble your larger string, but you must be cautious about word wrapping of your source code. Because JavaScript interpreters have a built-in feature that automatically inserts semicolons at the logical ends of source code lines, you cannot simply break a string with a carriage return character in the source code without putting the syntactically correct breaks in the code to indicate the continuation of a string value. For example, the following statement and format triggers a syntax error as the page loads:
var longString = "One piece " + "plus one
more piece.";
The interpreter treats the first line as if it were:
var longString = "One piece " + "plus one;
To the interpreter, this statement contains an unterminated string and invalidates both this statement and anything coming after it. To break the line correctly, you must terminate the trailing string, and place a plus operator as the final character of the physical source code line (do not put a semicolon there because the statement isn't finished yet). Also, be sure to start the next line with a quote symbol:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Accessing Substrings
NN 2, IE 3
You want to obtain a copy of a portion of a string.
Use the substring( ) method (in all scriptable browsers) to copy a segment starting at a particular location and ending either at the end of the string (omitting the second parameter does that) or at a fixed position within the string, counting from the start of the string:
var myString = "Every good boy does fine.";
var section = myString.substring(0, 10);    // section is now "Every good"
Use the slice( ) method (in NN 4 or later and IE 4 or later) to set the end position at a point measured from the end of the string, using a negative value as the second parameter:
var myString = "Every good boy does fine.";
var section = myString.slice(11, -6);       // section is now "boy does"
Use the nonstandard, but widely supported, variant called substr( ) to copy a segment starting at a particular location for a string length (the second parameter is an integer representing the length of the substring):
var myString = "Every good boy does fine.";
var section = myString.substr(6, 4);        // section is now "good"
If the sum of the two arguments exceeds the length of the string, the method returns a string from the start point to the end of the string.
Parameters for the ECMA-compatible slice( ) and substring( ) methods are numbers that indicate the zero-based start and end positions within the string from which the extract comes. The first parameter, indicating the start position, is required. When you use two positive integer values for the slice( ) method arguments (and the first argument is smaller than the second), you receive the same string value as the substring( ) method with the same arguments.
Note that the integer values for substring( ) and slice( ) act as though they point to spaces between characters. Therefore, when a
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Changing String Case
NN 2, IE 3
You want to convert a string to all upper- or lowercase letters.
Use the two dedicated String object methods, toLowerCase( ) and toUpperCase( ) , for case changes:
var myString = "New York";
var lcString = myString.toLowerCase( );
var ucString = myString.toUpperCase( );
Both methods return modified copies of the original string, leaving it intact. If you want to replace the value of a variable with a case-converted version of the original string (and thus eliminate the original string), reassign the results of the method to the same variable:
myString = myString.toLowerCase( );
Do not, however, redeclare the variable with a var keyword.
Because JavaScript strings (like just about everything else in the language) are case-sensitive, it is common to use case conversion for tasks such as testing the equivalency of a string entered into a text box by a user against a known string in your code. Because the user might include a variety of case variations in the entry, you need to guard against unorthodox entries by converting the input text to all uppercase or all lowercase letters for comparison (see Recipe 1.4).
Another common need for case conversion is preparing user entries for submission to a database that prefers or requires all uppercase (or all lowercase) letters. You can accomplish this for a user either at time of entry or during batch validation prior to submission. For example, an onchange event handler in a text box can convert the text to all uppercase letters as follows:
<input type="text" name="firstName" id="firstName" size="20" maxlength="25" 
    onchange="this.value = this.value.toUpperCase( )" />
Simply reassign a converted version of the element's value to itself.
Recipe 1.4 for a practical example of case conversion simplifying an important string task.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing Equality of Two Strings
NN 2, IE 3
You want to compare a user's text entry against a known string value.
Convert the user input to either all uppercase or all lowercase characters, and then use the JavaScript equality operator to make the comparison:
if (document.myForm.myTextBox.value.toLowerCase( ) =  = "new york") {
    // process correct entry
}
By using the results of the case conversion method as one of the operands of the equality expression, you do not modify the original contents of the text box. (See Recipe 1.3 if you want to convert the text in the text box to all of one case.)
JavaScript has two types of equality operators. The fully backward-compatible, standard equality operator (= =) employs data type conversion in some cases when the operands on either side are not of the same data type. Consider the following variable assignments:
var stringA = "My dog has fleas.";
var stringB = new String("My dog has fleas.");
These two variables might contain the same series of characters but are different data types. The first is a string value, while the second is an instance of a String object. If you place these two values on either side of an equality (= =) operator, JavaScript tries various evaluations of the values to see if there is a coincidence somewhere. In this case, the two variable values would show to be equal, and the following expression:
stringA =  = stringB
returns true.
But the other type of equality operator, the strict equality operator (= = =), performs no data type conversions. Given the variable definitions above, the following expression evaluates to false because the two object types differ, even though their payloads are the same:
stringA =  =  = stringB
If the logic of your code requires you to test for the inequality of two strings, you can use the inequality (
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing String Containment Without Regular Expressions
NN 2, IE 3
You want to know if one string contains another, without using regular expressions.
Use the JavaScript indexOf( ) string method on the longer string section, passing the shorter string as an argument. If the shorter string is inside the larger string, the method returns a zero-based index integer of the start position of the smaller string within the larger string. If the shorter string is not in the larger string, the method returns -1.
For logic that needs to branch if the smaller string is not contained by the larger string, use the following construction:
if (largeString.indexOf(shortString) =  = -1) {
    // process due to missing shortString
}
For logic that needs to branch if the smaller string is contained somewhere within the larger string, use the following construction:
if (largeString.indexOf(shortString) != -1) {
    // process due to found shortString
}
In either case, you are not interested in the precise position of the short string but simply whether it is anywhere within the large string.
You may also find the integer returned by the indexOf( ) method to be useful in a variety of situations. For example, an event handler function that gets invoked by all kinds of elements in the event-propagation (bubbling) chain wants to process events that come only from elements whose IDs begin with a particular sequence of characters. This is an excellent spot to look for the returned value of zero, pointing to the start of the larger string:
function handleClick(evt) {
    var evt = (evt) ? evt : ((window.event) ? window.event : null);
    if (evt) {
        var elem = (evt.target) ? evt.target : ((evt.srcElement) ? 
            evt.srcElement : null);
        if (elem && elem.id.indexOf("menuImg") =  = 0) {
            // process events from elements whose IDs begin with "menuImg"
        }
    }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing String Containment with Regular Expressions
NN 4, IE 4
You want to use regular expressions to know whether one string contains another.
Create a regular expression with the short string (or pattern) and the global (g) modifier. Then pass that regular expression as a parameter to the match( ) method of a string value or object:
var re = /a string literal/g;
var result = longString.match(re);
When a global modifier is attached to the regular expression pattern, the match( ) method returns an array if one or more matches are found in the longer string. If there are no matches, the method returns null.
To work this regular expression mechanism into a practical function, you need some helpful surrounding code. If the string you are looking for is in the form of a string variable, you can't use the literal syntax for creating a regular expression as just shown. Instead, use the constructor function:
var shortStr = "Framistan 2000";
var re = new RegExp(shortStr, "g");
var result = longString.match(re);
After you have called the match( ) method, you can inspect the contents of the array value returned by the method:
if (result) {
    alert("Found " + result.length + " instances of the text: " + result[0]);
} else {
    alert("Sorry, no matches.");
}
When matches exist, the array returned by match( ) contains the found strings. When you use a fixed string as the regular expression pattern, these returned values are redundant. That's why it's safe in the previous example to pull the first returned value from the array for display in the alert dialog box. But if you use a regular expression pattern involving the symbols of the regular expression language, each of the returned strings could be quite different, but equally valid because they adhere to the pattern.
As long as you specify the g modifier for the regular expression, you may get multiple matches (instead of just the first). The length of the array indicates the number of matches found in the longer string. For a simple containment test, you can omit the
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Searching and Replacing Substrings
NN 4, IE 4
You want to perform a global search-and-replace operation on a text string.
The most efficient way (for NN 4 or later and IE 4 or later) is to use a regular expression with the replace( ) method of the String object:
var re = /a string literal/g;
var result = mainString.replace(re, replacementString);
Invoking the replace( ) method on a string does not change the source string. Capture the changed string returned by the method, and apply the result where needed in your scripts or page. If no replacements are made, the original string is returned by the method. Be sure to specify the g modifier for the regular expression to force the replace( ) method to operate globally on the original string; otherwise, only the first instance is replaced.
To work this regular expression mechanism into a practical function, you need some helpful surrounding code. If the string you are looking for is in the form of a string variable, you can't use the literal syntax for creating a regular expression as just shown. Instead, use the constructor function:
var searchStr = "F2";
var replaceStr = "Framistan 2000";
var re = new RegExp(searchStr , "g");
var result = longString.replace(re, replaceStr);
In working with a text-based form control or an element's text node, you can perform the replace( ) operation on the value of the existing text, and immediately assign the results back to the original container. For example, if a div element contains one text node with scattered place holders in the form of (ph), and the job of the replace( ) method is to insert a user's entry from a text box (called myName), the sequence is as follows:
var searchStr = "\\(ph\\)";
var re = new RegExp(searchStr, "g");
var replaceStr = document.myForm.myName.value;
var div = document.getElementById("boilerplate");
div.firstChild.nodeValue = div.firstChild.nodeValue.replace(re, replaceStr);
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Using Special and Escaped Characters
NN 2, IE 3
You want to add low-order ASCII characters (tab, carriage return, etc.) to a string.
Use the escape sequences shown in Table 1-2 to represent the desired character. For example, to include an apostrophe inside a literal string, use \', as in:
var msg = "Welcome to Joe\'s Diner.";
The core JavaScript language includes a feature common to most programming languages that lets you designate special characters. A special character is not one of the plain alphanumeric characters or punctuation symbols, but has a particular meaning with respect to whitespace in text. Common characters used these days include the tab, newline, and carriage return.
A special character begins with a backslash, followed by the character representing the code, such as \t for tab and \n for newline. The backslash is called an escape character, instructing the interpreter to treat the next character as a special character. Table 1-2 shows the recognized escape sequence characters and their meanings. To include these characters in a string, include the backslash and special character inside the quoted string:
var confirmString = "You did not enter a response to the last " +
    "question.\n\nSubmit form anyway?";
If you want to use one of these symbols between variables that contain string values, be sure the special character is quoted in the concatenation statement:
var myStr = lineText1 + "\n" + lineText2;
Special characters can be used to influence formatting of text in basic dialog boxes (from the alert( ), confirm( ), and prompt( ) methods) and textarea form controls.
Table 1-2 shows the recognized escaped characters and their meanings.
Table 1-2: String escape sequences
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Reading and Writing Strings for Cookies
NN 2, IE 3
You want to use cookies to preserve string data from one page visit to the next.
Use the cookies.js library shown in the Discussion as a utility for saving and retrieving cookies. To set a cookie via the library, invoke the setCookie( ) function, passing, at a minimum, the cookie's name and string value as arguments:
setCookie ("userID", document.entryForm.username.value);
To retrieve a cookie's value, invoke the library's getCookie( ) function, as in:
var user = getCookie("userID");
Example 1-1 shows the code for the entire cookies.js library.
Example 1-1. cookies.js library
// utility function to retrieve an expiration date in proper
// format; pass three integer parameters for the number of days, hours,
// and minutes from now you want the cookie to expire (or negative
// values for a past date); all three parameters are required,
// so use zeros where appropriate
function getExpDate(days, hours, minutes) {
    var expDate = new Date( );
    if (typeof days =  = "number" && typeof hours =  = "number" && 
        typeof minutes =  = "number") {
        expDate.setDate(expDate.getDate( ) + parseInt(days));
        expDate.setHours(expDate.getHours( ) + parseInt(hours));
        expDate.setMinutes(expDate.getMinutes( ) + parseInt(minutes));
        return expDate.toGMTString( );
    }
}
   
// utility function called by getCookie( )
function getCookieVal(offset) {
    var endstr = document.cookie.indexOf (";", offset);
    if (endstr =  = -1) {
        endstr = document.cookie.length;
    }
    return unescape(document.cookie.substring(offset, endstr));
}
   
// primary function to retrieve cookie by name
function getCookie(name) {
    var arg = name + "=";
    var alen = arg.length;
    var clen = document.cookie.length;
    var i = 0;
    while (i < clen) {
        var j = i + alen;
        if (document.cookie.substring(i, j) =  = arg) {
            return getCookieVal(j);
        }
        i = document.cookie.indexOf(" ", i) + 1;
        if (i =  = 0) break; 
    }
    return "";
}
   
// store cookie value with optional details as needed
function setCookie(name, value, expires, path, domain, secure) {
    document.cookie = name + "=" + escape (value) +
        ((expires) ? "; expires=" + expires : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}
   
// remove the cookie by setting ancient expiration date
function deleteCookie(name,path,domain) {
    if (getCookie(name)) {
        document.cookie = name + "=" +
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Between Unicode Values and String Characters
NN 2, IE 3
You want to obtain the Unicode code number for an alphanumeric character or vice versa.
To obtain the Unicode value of a character of a string, use the charCodeAt( ) method of the string value. A single parameter is an integer pointing to the zero-based position of the character within the string:
var code = myString.charCodeAt(3);
If the string consists of only one character, use the 0 argument to get the code for that one character:
var oneChar = myString.substring(12, 13);
var code = oneChar.charCodeAt(0);
The returned value is an integer.
To convert an Unicode code number to a character, use the fromCharCode( ) method of the static String object:
var char = String.fromCharCode(66);
Unlike most string methods, this one must be invoked only from the String object and not from a string value.
ASCII values and Unicode values are the same for the basic Latin alphanumeric (low-ASCII) values. But even though Unicode encompasses characters from many written languages around the world, do not expect to see characters from other writing systems displayed in alert boxes, text boxes, or rendered pages simply because you know the Unicode values for those characters; the browser and operating system must be equipped for the language encompassed by the characters. If the character sets are not available, the characters generated by such codes will be question marks or other symbols. A typical North American computer won't know how to produce a Chinese character on the screen unless the target writing system and font sets are installed for the OS and browser.
Recipe 1.2 for other ways to extract single-character substrings.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Encoding and Decoding URL Strings
NN 6, IE 5.5(Win)
You want to convert a string of plain text to a format suitable for use as a URL or URL search string, or vice versa.
To convert a string consisting of an entire URL to a URL-encoded form, use the encodeURI( ) method, passing the string needing conversion as an argument. For example:
document.myForm.action = encodeURI(myString);
If you are assembling content for values of search string name/value pairs, apply the encodeURIComponent( ) method:
var srchString = "?name=" + encodeURIComponent(myString);
Both methods have complementary partners that perform conversions in the opposite direction:
decodeURI(encodedURIString)
decodeURIComponent(encodedURIComponentString)
In all cases, the original string is not altered when passed as an argument to these methods. Capture the results from the value returned by the methods.
Although the escape( ) and unescape( ) methods have been available since the first scriptable browsers, they have been deprecated in the formal language specification (ECMA-262) in favor of a set of new methods. The new methods are available in IE 5.5 or later for Windows and Netscape 6 or later.
These new encoding methods work by slightly different rules than the old escape( ) and unescape( ) methods. As a result, you must encode and decode using the same pairs of methods at all times. In other words, if a URL is encoded with encodeURI( ), the resulting string can be decoded only with decodeURI( ).
The differences between encodeURI( ) and encodeURIComponent( ) are defined by the range of characters that the methods convert to the URI-friendly form of a percent sign (%) followed by the hexadecimal Unicode value of the symbol (e.g., a space becomes
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Encoding and Decoding Base64 Strings
NN 2, IE 3
You want to convert a string to or from Base64 encoding.
Use the functions of the base64.js library shown in the Discussion. Syntax for invoking the two functions is straightforward. To encode a string, invoke:
var encodedString = base64Encode("stringToEncode");
To decode a string, invoke:
var plainString = base64Decode("encodedString");
Example 1-2 shows the entire base64.js library.
Example 1-2. base64.js library
// Global lookup arrays for base64 conversions
var enc64List, dec64List;
   
// Load the lookup arrays once
function initBase64( ) {
    enc64List = new Array( );
    dec64List = new Array( );
    var i;
    for (i = 0; i < 26; i++) {
        enc64List[enc64List.length] = String.fromCharCode(65 + i);
    }
    for (i = 0; i < 26; i++) {
        enc64List[enc64List.length] = String.fromCharCode(97 + i);
    }
    for (i = 0; i < 10; i++) {
        enc64List[enc64List.length] = String.fromCharCode(48 + i);
    }
    enc64List[enc64List.length] = "+";
    enc64List[enc64List.length] = "/";
    for (i = 0; i < 128; i++) {
        dec64List[dec64List.length] = -1;
    }
    for (i = 0; i < 64; i++) {
        dec64List[enc64List[i].charCodeAt(0)] = i;
    }
}
   
// Encode a string
function base64Encode(str) {
    var c, d, e, end = 0;
    var u, v, w, x;
    var ptr = -1;
    var input = str.split("");
    var output = "";
    while(end =  = 0) {
        c = (typeof input[++ptr] != "undefined") ? input[ptr].charCodeAt(0) : 
            ((end = 1) ? 0 : 0);
        d = (typeof input[++ptr] != "undefined") ? input[ptr].charCodeAt(0) : 
            ((end += 1) ? 0 : 0);
        e = (typeof input[++ptr] != "undefined") ? input[ptr].charCodeAt(0) : 
            ((end += 1) ? 0 : 0);
        u = enc64List[c >> 2];
        v = enc64List[(0x00000003 & c) << 4 | d >> 4];
        w = enc64List[(0x0000000F & d) << 2 | e >> 6];
        x = enc64List[e & 0x0000003F];
        
        // handle padding to even out unevenly divisible string lengths
        if (end >= 1) {x = "=";}
        if (end =  = 2) {w = "=";}
        if (end < 3) {output += u + v + w + x;}
    }
    // format for 76-character line lengths per RFC
    var formattedOutput = "";
    var lineLength = 76;
    while (output.length > lineLength) {
        formattedOutput += output.substring(0, lineLength) + "\n";
        output = output.substring(lineLength);
    }
    formattedOutput += output;
    return formattedOutput;
}
   
// Decode a string
function base64Decode(str) {
    var c=0, d=0, e=0, f=0, i=0, n=0;
    var input = str.split("");
    var output = "";
    var ptr = 0;
    do {
        f = input[ptr++].charCodeAt(0);
        i = dec64List[f];
        if ( f >= 0 && f < 128 && i != -1 ) {
            if ( n % 4 =  = 0 ) {
                c = i << 2;
            } else if ( n % 4 =  = 1 ) {
                c = c | ( i >> 4 );
                d = ( i & 0x0000000F ) << 4;
            } else if ( n % 4 =  = 2 ) {
                d = d | ( i >> 2 );
                e = ( i & 0x00000003 ) << 6;
            } else {
                e = e | i;
            }
            n++;
            if ( n % 4 =  = 0 ) {
                output += String.fromCharCode(c) + 
                          String.fromCharCode(d) + 
                          String.fromCharCode(e);
            }
        }
    } while (typeof input[ptr] != "undefined");
    output += (n % 4 =  = 3) ? String.fromCharCode(c) + String.fromCharCode(d) : 
              ((n % 4 =  = 2) ? String.fromCharCode(c) : "");
    return output;
}
   
// Self-initialize the global variables
initBase64( );
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Numbers and Dates
Designers of friendly scripting languages might have nonprogrammers in mind when they first define the scope of their languages, but it's difficult for any such language to be taken seriously by professional programmers unless some of the nerdy basics are there. Math may be anathema to scripters not schooled in computer science, but even an accessible language such as JavaScript has a solid complement of features to accommodate the kinds of arithmetic, trigonometric, and other operations typically supported by a programming language. Date manipulation—also numerically intensive, as it turns out—is well supported in JavaScript as well. This chapter includes recipes for both of these areas.
For most scripters, the interior details about how JavaScript treats numbers is of little importance. In fact, the more you know about programming languages and different types of numbers, the more you need to forget in order to use JavaScript numbers. Unlike other languages, JavaScript has only one kind of number data type. All integers and floating-point values are represented by the same data type in JavaScript: number .
Internally, a JavaScript number is an IEEE double-precision 64-bit value. JavaScript provides a usable range of number values from 2.2E-208 to 1.79E+308 (boundary values obtainable by the static Number object properties Number.MIN_VALUE and Number.MAX_VALUE, respectively). JavaScript treats numbers beyond these limits as infinity, represented by Number.NEGATIVE_INFINITY and Number.POSITIVE_INFINITY. It is unlikely that you will ever refer to these four properties in your scripts, but the language has them for the sake of completeness.
Number values do not carry any formatting with them. If a value needs places to the right of the decimal to signify a fractional part of an integer, those places are there. But if a variable that once held a number with 10 digits to the right of the decimal is modified through an arithmetic operation to become an integer, the decimal and zeros to the right of the decimal disappear.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introduction
Designers of friendly scripting languages might have nonprogrammers in mind when they first define the scope of their languages, but it's difficult for any such language to be taken seriously by professional programmers unless some of the nerdy basics are there. Math may be anathema to scripters not schooled in computer science, but even an accessible language such as JavaScript has a solid complement of features to accommodate the kinds of arithmetic, trigonometric, and other operations typically supported by a programming language. Date manipulation—also numerically intensive, as it turns out—is well supported in JavaScript as well. This chapter includes recipes for both of these areas.
For most scripters, the interior details about how JavaScript treats numbers is of little importance. In fact, the more you know about programming languages and different types of numbers, the more you need to forget in order to use JavaScript numbers. Unlike other languages, JavaScript has only one kind of number data type. All integers and floating-point values are represented by the same data type in JavaScript: number .
Internally, a JavaScript number is an IEEE double-precision 64-bit value. JavaScript provides a usable range of number values from 2.2E-208 to 1.79E+308 (boundary values obtainable by the static Number object properties Number.MIN_VALUE and Number.MAX_VALUE, respectively). JavaScript treats numbers beyond these limits as infinity, represented by Number.NEGATIVE_INFINITY and Number.POSITIVE_INFINITY. It is unlikely that you will ever refer to these four properties in your scripts, but the language has them for the sake of completeness.
Number values do not carry any formatting with them. If a value needs places to the right of the decimal to signify a fractional part of an integer, those places are there. But if a variable that once held a number with 10 digits to the right of the decimal is modified through an arithmetic operation to become an integer, the decimal and zeros to the right of the decimal disappear.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Between Numbers and Strings
NN 4, IE 4
You want to change a number data type to a string data type, or vice versa.
To convert a number value to a string value in Version 4 or later browsers, use the toString( ) method of a number value:
var numAsStringValue = numValue.toString( );
You can also create an instance of a String object by passing the number as an argument to the String object constructor:
var numAsStringObject = new String(numValue);
To convert a string to a number, use the parseInt( ) method if the desired result is an integer only, or the parseFloat( ) method if the number could be or is definitely a floating-point number:
var intValue = parseInt(numAsString, 10);
var floatValue = parseFloat(numAsString);
If you use parseFloat( ) and the number passed as an argument is an integer, the result will also be formatted as an integer, without a decimal and trailing zero. Both the parseInt( ) and parseFloat( ) functions work with all scriptable browser versions.
In many cases, the JavaScript interpreter tries to cast values between number and string data types automatically. For example, if you multiply a number times a string version of the number, the string is automatically converted to a number value, and the operation succeeds. This kind of casting doesn't always work, however. For instance, the addition (+) operator plays two roles in JavaScript: adding numbers and concatenating strings. When you place this operator between a number and a number that is actually a string value, the string wins the battle, and the two numbers get concatenated together as a string. Thus, the expression 2 + "2" equals "22" in JavaScript.
Most commonly, you need to convert a string to a numeric value when you perform math operations on values entered by the user in form text boxes. The
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing a Number's Validity
NN 3, IE 4
You want to be sure a value is a number before performing a math operation on it.
If the value you're testing can come from any kind of source, the safest bet is to use the typeof operator on the value. Applying this operator to any numeric value evaluates to the string number. Therefore, using it in a conditional expression looks like this:
if (typeof someVal =  = "number") {
    // OK, operate on the value numerically
}
But some JavaScript methods, such as parseInt( ) and parseFloat( ) , return a special value, NaN ("not a number"), signifying that they were unable to derive the number you desired. Operations expecting numeric operands or arguments that encounter values evaluating to NaN also generally return NaN. To test for this condition, use the isNaN( ) method, which returns true if the value is not a number. For example:
var myVal = parseInt(document.myForm.myAge.value);
if (isNaN(myVal)) {
    alert("Please check the Age text box entry.");
} else {
    // OK, operate on the value numerically
}
Don't get the wrong impression about the isNaN( ) method from the second example just shown. It is not a suitable approach to validating numeric input to a text box. That's because the parseInt( ) or parseFloat( ) methods return the first numbers (if any) they encounter in the string value passed as an argument. If someone enters 32G into a text box intended for an age, the parseInt( ) method pulls off the 32 portion, but the full value of the text box is not valid for your database that expects a strictly numeric value for that field. See Recipe 8.2 for more robust ways of validating numeric text entries.
You don't have to perform validity testing on absolutely every value about to undergo a math operation. Most values in your scripts tend to be under strict control of the programmer, allowing data-typing kinks to be worked out before the script is put into production. You need to exercise care, however, whenever user input enters the equation.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Testing Numeric Equality
NN 2, IE 3
You want to know whether two numeric values are equal (or not equal) before continuing processing.
Use the standard equality operator (= =) in a conditional statement:
if (firstNum =  = secondNum) {
    // OK, the number values are equal
}
Values on either side of the equality operator may be variables or numeric literals. Typical practice places the suspect value to the left of the operator, and the fixed comparison on the right.
JavaScript has two types of equality operators. The fully backward-compatible, standard equality operator (= =) employs automatic data type conversion in some cases when the operands on either side are not of the same data type. Consider the following variable assignments:
var numA = 45;
var numB = new Number(45);
These two variables might contain the same numeric value, but they are different data types. The first is a number value, while the second is an instance of a Number object. If you place these two values on either side of an equality (= =) operator, JavaScript tries various evaluations of the values to see if there is a coincidence somewhere. In this case, the two variable values would show to be equal, and the following expression:
numA =  = numB
returns true.
But the other type of equality operator, the strict equality operator (= = =), performs no data type conversions. Given the variable definitions above, the following expression evaluates to false because the two object types differ, even though their payloads are the same:
numA =  == numB
If one equality operand is an integer and the other is the same integer expressed as a floating-point number (such as 4 and 4.00), both kinds of equality operators find their values and data types to be equal. A number is a number in JavaScript.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Rounding Floating-Point Numbers
NN 2, IE 3
You want to round a floating-point value to the nearest whole number.
Use the Math.round( ) method on the value:
var roundedVal = Math.round(floatingPointValue);
The operation does not disturb the original value. Capture the rounded result in a variable.
The algorithm that the Math.round( ) method uses is that any floating-point value that is greater than or equal to x .5 is rounded up to x +1; otherwise, the returned value is x.
JavaScript's Math object contains some other useful methods for trimming floating-point numbers of their fractional parts. Math.floor( ) and Math.ceil( ) return the next lowest and next highest integer values, respectively. For example, Math.floor(3.25) returns 3, while Math.ceil(3.25) returns 4. With negative values, the rules still apply, but the results seem backward at first glance: Math.floor(-3.25) returns the next lowest integer, -4; Math.ceil(-3.25) returns -3. For positive values, you can use the Math.floor( ) method as a substitute for what some other languages treat as the integer of a number.
Anytime a floating-point number evaluates to a number equal to an integer value, the decimal and digits to the right of the decimal go away. A variable can hold a floating-point number in one statement and be modified to an integer in the next. This drives some programmers crazy because they were indoctrinated by other languages to treat each type of number as a different data type.
Section 2.0.2 in the introduction of this chapter.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Formatting Numbers for Text Display
NN 2, IE 3
You want to display the results of numeric calculations with a fixed number of digits to the right of the decimal.
Two recent additions to the JavaScript language (and ECMA standard) simplify the display of numbers with a specific number of digits. These methods are implemented in IE 5.5 or later for Windows and Netscape 6 or later. To obtain a string containing a number with digits to the right of the decimal, use the toFixed( ) method, as in the following:
document.myForm.total.value = someNumber.toFixed(2);
The argument to the toFixed( ) method is the number of digits to the right of the decimal. Even if the number is an integer, the resulting string has a decimal and two zeros to the right of the decimal.
To obtain a string containing a number with a total fixed number of digits, use the toPrecision( ) method, as in the following:
document.myForm.rate.value = someNumber.toPrecision(5);
The argument to the toPrecision( ) method is the total number of digits in the returned string value, including digits to the left and right of the decimal (the decimal is not counted). If the original value has fewer digits than the method argument calls for, the result is padded with zeros to the right of the decimal:
var num = 98.6;
var preciseNum = num.toPrecision(5);          // preciseNum is now 98.600
For older browsers, number formatting is a more cumbersome process, but one that can be encapsulated in the formatNumber( ) utility function shown in the Discussion. Invoke the function by passing either a number or string that can be cast to a number and an integer signifying the number of places to the right of the decimal for the returned string:
document.myForm.total.value = formatNumber(someNumber, 2);
The result from this function is intended for display on the page, not further calculation. Thus, error conditions are returned as strings that would be displayed in lieu of the formatted number.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Converting Between Decimal and Hexadecimal Numbers
NN 2, IE 3
You want to change a decimal number to its hexadecimal equivalent, and vice versa.
While the core JavaScript language provides facilities for going from hexadecimal to decimal, you need a custom function to go the other way.
To get a hexadecimal number as a string into its decimal equivalent, use the parseInt( ) method and specify the second parameter as 16:
var decimalVal = parseInt(myHexNumberValue, 16);
For myHexNumberValue, you can use either the hexadecimal characters for the number, or the format required for hexadecimal arithmetic in JavaScript: the hexadecimal characters preceded by 0x or 0X (a zero followed by an X). Here are some examples with string literals in the two formats:
var decimalVal = parseInt("1f", 16);
var decimalVal = parseInt("0x1f", 16);
To convert a decimal number (between 0 and 255) to a hexadecimal string equivalent, use the following function:
function dec2Hex(dec) {
    dec = parseInt(dec, 10);
    if (!isNaN(dec)) {
        hexChars = "0123456789ABCDEF";
        if (dec > 255) {
            return "Out of Range";
        }
        var i = dec % 16;
        var j = (dec - i) / 16;
        result = "0x";
        result += hexChars.charAt(j) + hexChars.charAt(i);
        return result;
    } else {
        return NaN;
    }
}
Because JavaScript automatically converts hexadecimal numbers to their decimal equivalents for arithmetic operations, the hexadecimal conversion is needed only for display of a hexadecimal result.
Hexadecimal arithmetic isn't used much in JavaScript, but the language provides rudimentary support for base 16 numbers. As long as you signify a hexadecimal number value with the leading 0x, you can perform regular arithmetic on that value to your heart's content. But be aware that the results of those operations are returned in base 10, which allows the odd possibility of using hexadecimal and decimal values in the same expression:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Generating Pseudorandom Numbers
NN 2, IE 3
You want to generate a random number.
The Math.random( ) method returns a pseudorandom number between 0 and 1. To calculate a pseudorandom integer value within a range starting with zero, use the formula:
var result = Math.floor(Math.random( ) * (n + 1);
where n is the highest acceptable integer of the range. To calculate a pseudorandom integer number within a range starting at a number other than zero, use the formula:
var result = Math.floor(Math.random( ) * (n - m + 1)) + m;
where m is the lowest acceptable integer of the range, and n is the highest acceptable integer of the range.
The previous examples focus on random integers, such as the kind you might use for values of a game cube (a die with numbers from 1 through 6). But you can remove the Math.floor( ) call to let the rest of the expression create random numbers with decimal fractions if you need them.
JavaScript's random number generator does not provide a mechanism for adjusting the seed to assure more genuine randomness. Thus, at best you can treat it as a pseudorandom number generator.
Section 2.0.2 in the introduction of this chapter.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Calculating Trigonometric Functions
NN 2, IE 3
You want to invoke a variety of trigonometric functions, perhaps for calculating animation paths of a positioned element.
JavaScript's Math object comes with a typical complement of functions for trigonometric calculations. Each one requires one or two arguments and returns a result in radians. Arguments representing angles must also be expressed in radians. The following statement assigns the sine of a value to a variable:
var sineValue = Math.sin(radiansInput);
All Math object methods must be invoked as methods of the static Math object.
See the introduction to this chapter for a summary of all Math object methods and constants. You can see an application of trigonometric functions in Recipe 13.10, which calculates the circular path for a positioned element to follow on the page.
Section 2.0.2 in the introduction of this chapter; Recipe 13.10 where some trigonometric operations help calculate points around a circular path.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating a Date Object
NN 2, IE 3
You want to create an instance of a Date object to use for date calculations or display.
Use the Date object constructor method with any of the acceptable arguments signifying a date (and, optionally, a time for that date):
var myDate = new Date(yyyy, mm, dd, hh, mm, ss);
var myDate = new Date(yyyy, mm, dd);
var myDate = new Date("monthName 
               dd, yyyy 
               hh:mm:ss");
var myDate = new Date("monthName 
               dd, yyyy");
var myDate = new Date(epochMilliseconds);
With all of these constructions, you can generate a date object for any point in history (reliably back to approximately 100 A.D.) or the future (thousands of millennia hence). When you create a date object without specifying the time, all time values are automatically set to zero—the very start of that day.
To create a date object with the current date and time, omit all arguments:
var now = new Date( );
The accuracy of the value assigned by the Date object constructor is entirely dependent upon the accuracy of the client computer's internal clock, control panel settings, and occasional browser anomalies. Correct setting of the computer's local time zone and daylight saving time option is essential to accurate date and time calculations based on the current date.
Notice that the arguments for the Date object constructor—as specified in the ECMAScript standard—have no variation that readily accepts shortcut ways of entering dates (such as mm / dd / yyyy, or the numerous variations used around the world). Instead, numerical entries need to be broken into the component parts to be passed as discrete arguments for the constructor. If you need to generate a date object from user entries in a text box (or, better still, a series of three text boxes), you can pass the value properties of those text boxes directly as arguments of the constructor:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Calculating a Previous or Future Date
NN 2, IE 3
You want to obtain a date based on a specific number of days before or after a known date.
The basic technique is to create a date object with a known date, and then add or subtract any number of units from that known date. After that, you can read the components of the modified date object to obtain the string or numerical representation of the date.
For example, we'll calculate the date that is 10 days from the current date. After creating a date object for now, a statement reads the date component (a calendar date within the month) and then sets the date value ahead by 10 days:
var myDate = new Date( );
myDate.setDate(myDate.getDate( ) + 10);
At this point, the myDate object contains the future date in milliseconds, irrespective of months, dates, and years. But if you then read myDate's string version (or locale string in recent browsers), you see the future date correctly calculated:
document.myForm.deadline.value = myDate.toLocaleDateString( );