Most programming tasks involve moving data around in memory. A lot of the data involved in browser-based JavaScript activity consists of objects that are part of the rendered document. But very often your scripts arrive at the client accompanied by data provided by a server or hardwired in the script (as arrays or custom objects). Or, you may find it convenient to create more flexible data structures that mirror the rendered content on the page. For example, it may be easier and faster to sort a table's data inside a JavaScript array and re-render the table rather than playing Tower of Hanoi games with cells and rows of a table one by one.
One of the most important jobs you have as a programmer is designing the data structures that your scripts will be working with. It's not unusual to start the planning of a major scripting job by scoping out the data structures that will facilitate DHTML-enhanced user interface features. When you do so, you will find JavaScript arrays and custom objects to be the containers and organizers of your data. These containers give your scripts a regular way to access the data points and a clean way to structure the data to make it easy to visualize the abstract comings and goings during script execution.
The loose data typing that pervades JavaScript carries over to arrays, but even more so. Unlike similar structures in many other programming languages, a JavaScript array is not limited to a specific size chiseled in stone at the time of its creation. You can add or delete items from an array at will. It is an extraordinarily flexible data store.
Another feature of the JavaScript array is that each entry in the array can hold data of any type. It's no problem mixing strings, numbers, Booleans, and objects within the same array. You can even change the data and data type for a single array entry at any time. Neither of these practices may be advisable from a programming-style point of view, but they're possible nevertheless.
Arrays are indexed by zero-based integers. In other words, to reference the first entry in an array named myArray, use myArray[0]. A reference to the array entry returns the entry's value. To assign a value to an entry, use the simple assignment (=) operator. You may also use the add-by-value (+=) operator to add a number or append a string to an array entry, as appropriate.
The basic JavaScript array is a one-dimensional kind of array. But, as you will see in Recipe 3.2 and Recipe 3.9, you can create more complex array structures, including multidimensional arrays (arrays of arrays), and arrays whose entries are complex custom objects.
The "looseness" of the JavaScript language, as exhibited in the way it handles data typing, arrays, and variable values, extends to its concept of objects. Forget what you know about object-oriented programming techniques and relationships between objects. The notions of traditional classes, subclasses, and message passing have little application in JavaScript (although some of these ideas may come to the language in the future). Instead, think of a custom object as simply a convenient container for data in which the data values have labels that make it easier to remember what's what. Custom object syntax is just like the syntax you use for other JavaScript and DOM objects: it follows the "dots" rule (e.g., myObject.myProperty and myObject.myMethod( )).
One of the hazards of bringing too much object-oriented programming experience to scripting is that you might tend to turn every piece of data into an object, even when the overhead (in terms of source code space) to generate the object outweighs any functional or readability benefit you might get from using objects. It's not uncommon for an object-oriented approach to a simple problem to obfuscate the relationships among data points. But if your scripts frequently need to refer to some data associated with an entity that hangs around in the global variable space, it probably makes good sense to use an object there. In later chapters of this book, you will see many objects used as repositories for bits of information related to a particular item, such as the details of a drop-down menu.
Despite the cautions expressed here about the difference between objects in JavaScript (which are based on a concept called prototype inheritance) and true object-oriented environments, you can simulate a goodly amount of genuine OOP ideas with custom objects. Recipe 3.12 demonstrates a few of these simulations.
So, when do you use an array, and when do you use an object? Think of an array as an ordered list of similar kinds of data. The list, itself, signifies the purpose or kind of data it contains, such as a series of coworker names or the titles of all books on a shelf. The position of one item among the others is not important, although you might like to sort the list to, perhaps, show the contents in alphabetical order. Having the items in this kind of "blind" list means that at some point you will be looking through all items in the list, perhaps to pull out their values for insertion into an HTML element for display.
An object, on the other hand, is best used to encapsulate information about a single entity. A coworker object might contain properties for the person's name and age; a book object could have dozens of properties for information points such as title, author, publisher, category, and so on. The properties are explicitly named so that you can readily access the value of a single property directly (e.g., book3.publisher). You can also equip an object with methods whose actions operate on the object and its properties (see Recipe 3.8).
As you will see in Recipe 3.7 and elsewhere, there is an advantage in creating an array of objects. The "array-ness" gives your scripts the ability to iterate through the entire list of objects; the "object-ness" lets the same script inspect a specific property of each object in the array to perform tasks like lookups. An array of book objects, for instance, lets a looping construct look through the entire list of books and inspect the author property of each item to accumulate the title property values of those objects whose author property meets a particular criterion.
Be prepared to use arrays and objects by themselves, as well as in combination. Not only are you likely to use an array of objects, but a property of an object may be an array. For example, an object that represents a book might define the author property as an array to accommodate multiple authors. A book with a single author has a one-entry array for that property, but the scripts that go diving for authors know to expect an array data type there, as well as use appropriate comparison tools against the entries in the array.
As dry as this chapter's subject may seem at first glance, it may be the most important one in the entire book. Most of the recipes from this chapter are used in later chapters repeatedly because they are fundamental building blocks for a lot of Dynamic HTML and other scripting.
Most of the recipes in this chapter show data arrays and objects embedded directly within the page of the examples. This approach works for a fixed set of data or, after the page has loaded, data dynamically read from the page or user entry forms. But you can also embed data from live sourcesserver databaseswith the help of server programming.
If you use a server environment (such as ASP, JSP, ColdFusion, PHP, and many more) that assembles each page's content by way of server-side templates and programs, you can use the same environment to retrieve data from your databases and convert the returned data sets into JavaScript arrays and objects to be delivered with the rest of the page. Another approach is to let the external script-loading capability of browsers (via the src attribute of the <script> tag) point to a server process URL. The URL contains query data that the server program uses to fetch the database data, then the server converts the returned data into JavaScript arrays and objects for output to the client, delivered in the format and MIME type of a .js file. The data becomes part of the page's scripts, just as if it were directly embedded in the page.
Even more elaborate schemes are possible. A hidden frame that repeatedly queries the server can retrieve continually updated data that comes back as JavaScript data-enhanced web pages. And hidden Java applets can keep an open socket with a server process and communicate the data to the page (in browsers that support LiveConnectJava-to-JavaScripttechnology). All of these approaches have the same goal: to embed data as JavaScript arrays and/or objects for easy access and manipulation in a Dynamic HTML client environment.