Team LiB
Previous Section Next Section

Generic and User-Defined Objects

In addition to explaining how to declare built-in objects like Strings and Arrays, Chapter 4 also alluded to the creation of Object objects. These generic objects can be used to create user-defined data types, and they are therefore one of the most powerful tools available for writing non-trivial JavaScripts.

As with any objects in JavaScript, you can add properties to Objects dynamically:

var robot = new Object();
robot.name = "Zephyr";
robot.model = "Guard";
robot.hasJetpack = true;

You can, of course, also add functions dynamically. The following code extends the previous simple example by adding a method to the robot object. We first define the function and then add it to the object:

function strikeIntruder() 
{
   alert("ZAP!");
}
robot.attack = strikeIntruder();

Notice that we named the method attack even though the function was named strikeIntruder. We could have named it anything; the interpreter does not care what identifier we choose to use. When we invoke the method,

robot.attack();

we get the result:

We could have written this example without even naming the function we called strikeIntruder. Recall from Chapter 5 that JavaScript 1.2+ supports function literals. Here

we restate our example using this capability:

var robot = new Object();
robot.name = "Zephyr";
robot.model = "Guard";
robot.hasJetpack = true;
robot.attack = function()
                   {
                      alert("ZAP!");
                   };

This syntax is more compact and avoids cluttering the global namespace with a function that will be used only as a method of a user-defined object. It also illustrates one of the most popular uses of generic Objects: to group together related pieces of data in a consistent fashion. For example, if you had multiple distinct robot models you wished to display to the user, placing the information for each model in a separate Object with a consistent property naming scheme can make your code more readable and easier to maintain.

Object Literals

Because JavaScript supports literal syntax for many data types (e.g., numbers, strings, arrays, and functions), it should come as no surprise that Object literals are supported in JavaScript 1.2+. The syntax is a curly braces–enclosed, comma-separated list of property/value pairs. Property/value pairs are specified by giving a property name followed by a colon and then its value. Here, we restate the previous example using both object and function literals:

var robot = { name: "Zephyr ",
              model: "Guard",
              hasJetpack: true,
              attack: function() { alert("ZAP!"); }
             };

And we can invoke robot.attack() with the same result as before.

This example also hints at the robustness of these capabilities. It is perfectly valid to specify nested literals, properties with null or undefined values, and values that are not literals (that is, values that are variables). The following code illustrates these concepts in an example similar to those we’ve previously seen:

var jetpack = true;
var robot = { name: null,
              hasJetpack: jetpack,
              model: "Guard",
              attack: function() { alert("ZAP!"); },
              sidekick: {  name: "Spot",
                           model: "Dog",
                           hasJetpack: false,
                           attack: function() { alert("CHOMP!"); }
                        }
            };
robot.name = "Zephyr";

There is a fair amount going on here that might require explanation. First, notice that robot’s property hasJetpack is set through another variable, jetpack. Also note that the robot.name is initially set to null, but it is later filled in with the appropriate value. The major change is that robot contains a nested object called sidekick, which also contains four properties, name, model, hasJetpack, and an attack method. Invoking robot.attack() results in the now-familiar “ZAP!” output. The method call

robot.sidekick.attack();

results in

If the way the robot object has been defined in the previous examples seems bulky and inelegant to you, your programming instincts are very good. There is a better way to create your own objects that makes much better use of the object-oriented nature of JavaScript. We’ll explore that a little later in the chapter, but for now these examples should illustrate the options you have with regard to object definition. Before moving on, let’s take a look at an alternative way to reference objects.

Objects as Associative Arrays

An associative array is a data structure that enables you to associate data with names. Elements in a normal array are addressed by the integer indicating their index. Elements in an associative array are addressed by names that are strings. For example, you might have an associative array indexed by name (a string) that gives you a customer’s address or phone number. Associative arrays are a convenient way to simplify “data lookup” tasks.

JavaScript provides associative arrays as a consequence of the fact that the following two statements are equivalent:

object.property

object["property"]

Associative arrays in JavaScript are merely objects used with the array syntax, and key/value pairs are merely instance property names and values. To store values in an array, we might do something like this:

var customers = new Object();
customers["John Doe"] = "123 Main St., Metropolis, USA";

And to retrieve it:

var address = customers["John Doe"];

Storing a string in customers["John Doe"] was an arbitrary decision. Data of any type may be placed in an associative array.

Associative arrays are most commonly used when property names are not known until runtime. For example, you might have a loop that prompts the user to enter customer names and addresses. The actual storage of the data (inside the loop) might look like this:

customerName = prompt("Enter name", "");
customerAddress = prompt("Enter address", "");
customers[customerName] = customerAddress;

In this example, both customerName and customerAddress are strings, but there’s no reason that customerAddress couldn’t be some other kind of data, for example, a user-defined object storing address information.

In addition to the direct way elements may be accessed, JavaScript’s for/in construct is perfect for iterating over the elements of associative arrays. The following example loops through all elements of an array and prints them out:

var customers = new Object();
customers["Tom Doe"] = "123 Main St., Metropolis, USA";
customers["Sylvia Cheung"] = "123 Fake St., Vancouver B.C., Canada";
customers["George Speight"] = "145 Baldwin St., Dunedin, NZ";

for (var client in customers) 
{
   document.writeln("The address of client " + client + " is:");
   document.writeln(customers[client]);
   document.writeln("<<br />><<br />>");
}

Each name that has data associated with it is assigned to client, one at a time. This variable is used to access the data in the array. The output of the previous example is shown in Figure 6-4.

Click To expand
Figure 6-4: Associative arrays provide key/value data lookup capabilities in JavaScript.

Now that we’ve covered the fundamentals of how objects behave and how you can create and manipulate generic objects, it’s time to explore JavaScript’s object-oriented features. These features enable you to structure your scripts in a mature fashion similar to more mainstream application development languages such Java and C++. JavaScript’s object-oriented features aren’t as flexible as these languages, but you’ll probably find that what JavaScript has to offer is well suited to the kinds of tasks required when writing large scripts or building Web-based applications.


Team LiB
Previous Section Next Section