Web Development Tutorials




  
  

Objects as Associative Arrays

Arrays are one-dimensional storage areas, holding single data values in each of its elements. Many application, though, require more complex data structures, resembling, for example, the organization of data within a database table. Suppose you wish to store the following table of employee information so that your page can calculate a weekly payroll.

Employee Database
Time Sheet Entry
ID Hours


Figure 6-21. Using an array to store data objects.


You can enter employee ID values and weekly hours worked to update the table with current calculations. In the above example, for instance, enter "11111" in the ID textbox and "40.5" in the Hours textbox and click the "Enter Hours" button. The calculations are made and the table is updated. You can continue entering weekly hours for all employees to complete calculations for the entire table.

Creating an Object

The above table is an array; however, it is an array of objects. By creating your own objects—rather than relying on built-in JavaScript objects—you can create data structures to hold just about any organization of data you need. Although JavaScript is not a full-featured object-oriented programming language, it does give you features for making your own objects with their own properties and methods. You can script these objects just like you do other JavaScript objects.

Objects are created with a constructor function. This function is written very much like other JavaScript functions. Its purpose, though, is to describe an object and the properties and methods that compose it. It can be viewed as a class definition, providing the model for creating, or instantiating, objects containing actual data values for its properties and actual functions for its methods.

The constructor function for the above employee table is shown below.


function employee(idValue, nameValue, payRateValue)
{
  this.id = idValue;
  this.name = nameValue;
  this.payRate = payRateValue.toFixed(2);
  this.hours = 0;
  this.pay = 0;
}

Listing 6-16. Code to construct a data object.

Each of the this.name entries (i.e., id, name, payRate, hours, and pay) identify properties that make up an employee object. They equate to the names of the fields in the table. In this case, they are property names that point to assigned data values.

The function's arguments (idValue, nameValue, payRateValue) are the variables through which scripts supply data values for the properties when an object is created. That is, a script sends an id value, a name, and a payRate to the function. The function then instantiates an actual object, following this model, in which the properties take on the supplied values. Thereafter, references to the newly created object's id, name, and payRate properties point to their actual stored values.

Take, for instance, the use of this function to create an actual employee object with the statement


employee01 = new employee("11111", "A. Allen", 10.00);

Function employee is called to create a new object named employee01 (a programmer-supplied object name). The values "11111", "A. Allen", and 10.00 are passed to the constructor. The constructor receives these values through arguments idValue, nameValue, and payRateValue, which it assigns to the id, name, and payRate properties of the new object. Subsequently, a script reference to employee01.id (using dotted notation) produces the value "11111", a reference to employee01.name produces "A. Allen", and a reference to employee01.payRate produces 10.00. Similar objects can be created for the other employees, named perhaps employee02, employee03, and so forth.

The constructor function is passed only three values in this example. There are, however, two other properties of the object that are set to default values since passed values are not supplied. hours and pay are assigned 0 values in the constructor. This is because these property value are not yet know. They are produced later when the weekly "time sheet" is entered.

After the constructor is called for each of the five example employees, five objects exist. These five objects and their property settings are shown below.



employee01
     id = "11111"
     name = "A. Allen"
     payRate = 10.00
     hours = 0
     pay = 0

employee02
     id = "22222"
     name = "B. Brown"
     payRate = 15.00
     hours = 0
     pay = 0
   
employee03
     id = "33333"
     name = "C. Collins"
     payRate = 20.00
     hours = 0
     pay = 0
   
employee04
     id = "44444"
     name = "D. Davis"
     payRate = 25.00
     hours = 0
     pay = 0
   
employee05
     id = "55555"
     name = "E. Evans"
     payRate = 30.00
     hours = 0
     pay = 0

Figure 6-22. Data objects created through a constructor function.

Notice that this data structure can be easily visualized as a database table, with each row containing an employee record and each column being a data field within that record.

Creating an Object Array

The only problematic part of this data structure is that each "record" (each object) has a different name. This makes it difficult to iterate the structure within a loop to process the objects. There is no "index" value to be iterated. Each object must be accessed and processed as a separate entity.

However, these objects can be loaded into an array so they can be indexed. The constructor function is called as shown in the following script.


var employeeDB = new Array();

function employee(idValue, nameValue, payRateValue)
{
  this.id = idValue;
  this.name = nameValue;
  this.payRate = payRateValue.toFixed(2);
  this.hours = 0;
  this.pay = 0;
}

function addEmployees()
{
  employeeDB[employeeDB.length] = new employee("11111", "A. Allen", 10.00);
  employeeDB[employeeDB.length] = new employee("22222", "B. Brown", 15.00);
  employeeDB[employeeDB.length] = new employee("33333", "C. Collins", 20.00);
  employeeDB[employeeDB.length] = new employee("44444", "D. Davis", 25.00);
  employeeDB[employeeDB.length] = new employee("55555", "E. Evans", 30.00);
}

Listing 6-17. Code to create an array of data objects.

First, create a new global array named employeeDB (implying that it is structured like a database table) that is accessible by all of the processing functions. The addEmployees() function calls the constructor five times, once for each of the five employees. Rather than assigning five different names for the new objects, the objects are loaded into array employeeDB, becoming identified as employeeDB[0] through employeeDB[4].

Notice that the array element into which an object is placed is always given by the array's length property. When the array is first declared its length is 0. Therefore, the first assignment is to element employeeDB[0]. Now the array has a length of 1. So, the next assignment is to element employeeDB[1]. The array now has a length of 2 for assignment of the next object to employeeDB[2], and so forth. Using the array's increasing length is an easy way to always assign a new value (a new object in this case) to the next available element in an array.

The array of objects is built when the page is loaded. The <window> object has an onload event handler to call the init() function (see below), in which addEmployees() and showEmployees() functions are called to load and display the array.


function init(){
	addEmployees(); 
	showEmployees();
}

window.onload = init;

You now have an array of objects, each element of which contains five properties. You can visualize the data structure in virtually the same way you do a database table.

EmployeeDB
Object
Index
Property
ID Name Pay Rate Hours Weekly Pay
0 11111 A. Allen 10.00 0 0
1 22222 B. Brown 15.00 0 0
2 33333 C. Collins 20.00 0 0
3 44444 D. Davis 25.00 0 0
4 55555 E. Evans 30.00 0 0

Figure 6-23. Visualizing an array of data objects as a database table.

Since the objects are in an array, each can be indexed. Therefore, a loop can be used to access each of the objects and each of its properties. For example, to display the contents of the array the following function is used. It employs a for loop to iterate the array, displaying property values for the objects in table cells.


function showEmployees()
{
  var outString = ""
  sutString += 
    "<table border='1'>" +
    "<tr>" +
    "   <th>ID</th>" +
    "   <th>Name</th>" +
    "   <th>PayRate</th>" +
    "   <th>Hours</th>" +
    "   <th>Weekly Pay</th>" +
    "</tr>";
	
  for (i=0; i < employeeDB.length; i++) {
    outString += 
      "<tr>" +
      "   <td>" + employeeDB[i].id + "</td>" +
      "   <td>" + employeeDB[i].name + "</td>" +
      "   <td align='right'>" + employeeDB[i].payRate + "</td>" +
      "   <td align='right'>" + employeeDB[i].hours + "</td>" +
      "   <td align='right'>" + employeeDB[i].pay + "</td>" +
      "</tr>";
  }
	
  outString += "</table>";
  document.getElementById("outputTable").innerHTML = outString;
}

Listing 6-18. Code to display an array of data objects.

Notice that property values ("record fields") are accessed in the format: employeeDB[i].property. This reference extracts the named property from the object in the ith element of the array.

Being able to create data structures in this fashion gives you great flexibility in storing and processing data. Don't forget, though, that arrays are temporary storage containers. Arrays and their objects exist only as long as the page is loaded, unlike databases, which exist apart from the page and maintain their data indefinitely. This means that you cannot "update" the data structure and expect the new values to be there the next time you load the page. To accomplish that type of database maintenance requires server-based scripts and database management systems.

Accessing Object Properties

Still, there is great convenience in using array objects even for temporary processing. You can, for instance, use other scripts to input a "time sheet" and calculate the payroll for each of the employees. The interest might not be in saving this information, just having it in a form that is conveniently processed and displayed.

The data input area for the current application is used for this purpose and is given by the following code.


<table border="1">
<tr>
  <th>ID</th>
  <th>Hours</th>
</tr>
<tr>
  <td>
    <input id="employeeID" type="text" style="width:50px" maxlength="5"/>
  </td>
  <td>
    <input id="employeeHours" type="text" style="width:40px" maxlength="4"/>
  </td>
</tr>
</table>

<input type="button" value="Enter Hours" id="enterHoursBtn"/>

Listing 6-19. Code to display data entry form.

When an employee id and hours-worked amount is entered into the form and the "Enter Hours" button is clicked, the enterHours() function is called. This function calculates the pay amount as shown below. To make the "Enter Hours" button work, statements, which link the enterHours() function to the click event of the button, need to be added to the init() function as you can see below


function enterHours()
{
  for (i=0; i<employeeDB.length; i++) {
    if (employeeDB[i].id == document.getElementById("employeeID").value) {
      employeeDB[i].hours = document.getElementById("employeeHours").value;
      employeeDB[i].pay = employeeDB[i].payRate * employeeDB[i].hours;
      employeeDB[i].pay = employeeDB[i].pay.toFixed(2);
      break;
    }
  }
  document.getElementById("employeeID").value = "";
  document.getElementById("employeeHours").value = "";
  document.getElementById("employeeID").focus();
	
  showEmployees();
}

function init()
{
  addEmployees(); 
  showEmployees();
	
  // the following statements need to be added to make the "Enter Hours" button working
  var enterHoursBtn = document.getElementById("enterHoursBtn");
  enterHoursBtn.onclick = enterHours;
}

Listing 6-20. Code to calculate employee payroll.

The array is iterated to find a match of the id property of the employee object to the id value entered into the textbox. When found, the hours worked from the textbox is assigned to the hours property of the object. Then the employee's payRate property is multiplied by the hours property to get the pay property. The loop breaks since there's no reason to search further.

To complete its housekeeping tasks, the function clears the input areas and puts a blinking cursor back into the id field. For visual verification that the calculation has been made, the showEmployees() function is called to redisplay the table.

Object Methods

Objects can have methods as well as properties. A method is created by first creating a function. For example, consider the enterHours() and displayEmployees() functions previously described. To adopt these functions as object methods, the constructor includes references to them as shown in the last two lines of the following rewrite.


function employee(idValue, nameValue, payRateValue)
{
  this.id = idValue;
  this.name = nameValue;
  this.payRate = payRateValue.toFixed(2);
  this.hours = 0;
  this.pay = 0;
	
  this.add = enterHours;
  this.show = displayEmployees;
}

Listing 6-21. Adding methods to an object constructor.

Methods are included in each employee's object; thus, they are invoked through those objects. For instance, inside the enterHours() function, while an array index value is in force, the show method would be invoked with


employeeDB[i].show();

to display the output table. For this application, though, the methods are not associated with an individual object being processed. Therefore, they remain as stand-alone functions, not object methods.

An expanded version of this application, though, could use object methods. For example, a withholding deduction could be calculated for each employee. A new this.withholding property could be defined for the data object. Its value would be derived from an object method, say, this.calcWithhold, which is a call to the like-named function that looks up the withholding amount for an individual from withholding tables built into the function.

Applying Array Methods

An object array, like any other array, can used the built-in array methods discussed previously. For example, the employeeDB array can be sorted in descending or ascending sequence. The following two functions sort this array on the id property.


function sortDESC()
{
  employeeDB.sort(
    function(a,b){ return b.id - a.id; }
  );
  showEmployees();
}

function sortASC()
{
  employeeDB.sort(
    function(a,b){ return a.id - b.id; }
  );
  showEmployees();
}

Listing 6-22. Code to sort and redisplay the employeeDB array.

When sorting object arrays, the comparison function needs to know on which of the properties to sort. In this example, the function arguments { return b.id - a.id; } and { return a.id - b.id; } identify the id property for the sort comparison. Clicking the following buttons calls these functions and redisplays the output table. Scroll to the top of this page to view the results.



TOP | NEXT: Chapter 7 - Browser Objects