3.8 Creating a Custom Object
NN 3, IE 4
3.8.1 Problem
You want
to create a custom object for your data structure.
3.8.2 Solution
As with creating arrays, object creation has both a long form and a
compact form. The long form requires that you define a constructor
function, while the compact form uses special inline symbols to
denote the structure of the object.
A constructor
function looks like any other JavaScript
function, but its purpose is to define the initial structure of an
object—it's property and method
names—and perhaps to populate some or all of the properties
with initial values. Values to be assigned to properties of the
object are typically passed as parameters to the function, and
statements in the function assign those values to properties.
The following constructor function
defines an object with two properties:
function coworker(name, age) {
this.name = name;
this.age = age;
}
To create objects with this constructor, invoke the function with the
new keyword:
var emp1 = new coworker("Alice", 23);
var emp2 = new coworker("Fred", 32);
The this keyword in the constructor function
localizes the context of the function to the object being created. As
the function is reused for each object it creates, the context limits
itself just to the one object under construction.
If you prefer not to use a constructor function, you can create
objects with a shortcut syntax (Version 4 browsers or later) that
defines an object inside curly braces. Property names and values are
defined inside the curly braces as name/value pairs with a colon
between the name and value, and each pair is comma-delimited. For
example, the two objects just shown can be created using the shortcut
syntax as follows:
var emp1 = {name:"Alice", age:23};
var emp2 = {name:"Fred", age:32};
After the objects are created, you access a property value just like
you do with other JavaScript objects. For example, to display data
from the emp2 object in an alert dialog box, the
statement looks like the following:
alert("Employee " + emp2.name + " is " + emp2.age + " years old.");
After an object exists, you can add a new property to that instance
by simply assigning a value to the property name of your choice. For
example, to add a property about the cubicle number for Fred, the
statement is:
emp2.cubeNum = 320;
After that assignment, only emp2 has that property
(see Recipe 3.12 for more powerful assignments). There is no
requirement that a property be predeclared in its constructor or
shortcut creation code. This also means that you can be quite
cavalier in your object creation to the point of generating a blank
object and then populating it explicitly property by property:
var emp1 = new Object( );
emp1.name = "Alice";
emp1.age = 23;
This kind of object creation is usually more difficult to maintain in
the source code and also takes up much more space if you need to
create many similar objects.
3.8.3 Discussion
We've covered how to create properties for a custom
object. Doing the same with
methods is no more difficult. All it
requires is that the method initially be defined in your source code
as a JavaScript function; then assign a reference to that function as
a value for a method name in either the constructor function or
name/value pair inside curly braces. Continuing with the simple
employee objects just shown, let's add a method to
the object that displays an alert dialog box with the
employee's name and age. Begin by defining the
function that will do the work when invoked through one of the
objects:
function showAll( ) {
alert("Employee " + this.name + " is " + this.age + " years old.");
}
Then assign the function to a method name in the constructor function:
function coworker(name, age) {
this.name = name;
this.age = age;
this.show = showAll;
}
Or add the assignment to the shortcut constructors:
var emp1 = {name:"Alice", age:23, show:showAll};
var emp2 = {name:"Fred", age:32, show:showAll};
To invoke the method, do so via one of the objects:
emp1.show( );
Note how the context of the object passes through to the function
when it is invoked as a method of the object. The
this keywords in the function definition
point back to the context of the object that invoked the method, and
thus has immediate access to its companion properties.
JavaScript, as implemented in IE 4 and later or Navigator 4 and
later, provides an extra shortcut operator in constructor functions
that lets you automatically assign a default value to any property
that has a null value passed to it in the
function's parameter variables. For example, in the
coworker object constructor function, if the
statement that invokes the function leaves the second parameter
blank, the age parameter variable is initialized
as a null value. To provide a valid but harmless
default value (of zero) to that property, the syntax is as follows:
function coworker(name, age) {
this.name = name;
this.age = age || 0;
this.show = showAll;
}
The operator is the regular JavaScript OR operator. If the first
value is null or undefined, the second value is
assigned to the property. You can use this construction in any
variable assignment in JavaScript.
One advantage to the longer constructor function approach is that you
can include calls to other functions from inside the constructor. For
example, you might wish to invoke some initialization routines with
the object immediately as it is being created. Simply add the call to
the function as another statement inside the constructor function.
You can even pass a reference to the object under construction by
passing this as a parameter. The following example
builds on the coworker( ) constructor function
previously shown. A separate function displays an alert dialog box
each time an object is created:
function verify(obj) {
alert("Just added " + obj.name + ".");
}
function coworker(name, age) {
this.name = name;
this.age = age;
this.show = showAll;
verify(this);
}
If the external function returns a value, the constructor function
can assign that value to a property of the object.
If you are going to the trouble of creating a constructor function
for a complex data structure, more than likely you are doing it for
multiple instances of that object. But instead of having these
objects floating around the window's scripting space
as independent global variables, it will probably be more convenient
to store these objects in an array of objects. As shown in Recipe 3.4, the array data structure facilitates iterating through a
collection of similar items. For example, you could use an array of
coworker objects to look through all records in
search of those coworkers within a specific age range, and accumulate
the names of those who meet your criteria.
Very little extra is needed to generate an array of objects while you
are in the process of generating the objects themselves. The
following demonstrates how a series of calls to a constructor
function can be blended into an array constructor:
var employeeDB = new Array( );
employeeDB[employeeDB.length] = new coworker("Alice", 23);
employeeDB[employeeDB.length] = new coworker("Fred", 32);
employeeDB[employeeDB.length] = new coworker("Jean", 28);
employeeDB[employeeDB.length] = new coworker("Steve", 24);
You can do the same with shortcut syntax:
var employeeDB = new Array( );
employeeDB[employeeDB.length] = {name:"Alice", age:23, show:showAll};
employeeDB[employeeDB.length] = {name:"Fred", age:32, show:showAll};
employeeDB[employeeDB.length] = {name:"Jean", age:28, show:showAll};
employeeDB[employeeDB.length] = {name:"Steve", age:24, show:showAll};
Or you can go the whole route with shortcut syntax (albeit with one
long statement):
var employeeDB = [{name:"Alice", age:23, show:showAll},
{name:"Fred", age:32, show:showAll},
{name:"Jean", age:28, show:showAll},
{name:"Steve", age:24, show:showAll}];
Finally, here's the function that looks for all
coworkers in a certain age group:
function findInAgeGroup(low, high) {
var result = new Array( );
for (var i = 0; i < employeeDB.length; i++) {
if (employeeDB[i].age >= low && employeeDB[i].age <= high) {
result = result.concat(employeeDB[i].name);
}
}
return result;
}
This function returns an array of the names of those whose ages fall
between the low and high values passed as parameters.
As discussed in Recipe 3.9 and Recipe 3.11, an array of objects is one of
the most flexible complex data structures available to JavaScript
coders. During the design phase of your applications, look for
opportunities to group together similar objects in arrays.
3.8.4 See Also
Recipe 3.9 for generating a fast hash table from an array of objects;
Recipe 3.11 for sorting an array of objects based on object property
values.
|