Object-based programming is a slightly scarier way of saying programming using objects. But what are these objects that we will be programming with? Where are they, and how and why would we want to program with them? In this section, we'll look at the answers to these questions, both in general programming terms and more specifically within JavaScript.
To start our introduction to objects, let's think about what is meant by an object in the "real world" outside computing. The world is composed of things, or objects, such as tables, chairs, and cars (to name just a few!). Let's take a car as an example, so we can explore what an object really is.
How would we define our car? We might say it's a blue car with four-wheel drive. We might specify the speed at which it's traveling. When we do this, we are specifying properties of the object. For example, the car has a color property, which in this instance has the value blue.
How do we use our car? We turn the ignition key, press the gas pedal, beep the horn, change the gear (that is, choose between 1, 2, 3, 4, and reverse on a manual car, or drive and reverse on an automatic), and so on. When we do this, we are using methods of the object.
We can think of methods as being a bit like functions. Sometimes, we may need to use some information with the method, or pass it a parameter, to get it to work. For example, when we use the changing gear method, we need to say which gear we want to change to. Other methods may pass information back to the owner. For example, the dipstick method will tell the owner how much oil is left in the car.
Sometimes using one or more of the methods may change one or more of the object's properties. For example, using the accelerator method will probably change the car's speed property. Other properties can't be changed; for example, the body shape property of the car (unless you hit a brick wall with the speed property at 100 miles per hour!).
We could say that the car is defined by its collection of methods and properties. In object-based programming, the idea is to model real-world situations by objects, which are defined by their methods and properties.
You should now have a basic idea of what an object is—a "thing" with methods and properties. But how do we use this in JavaScript?
In the previous chapters, we have (for the most part) been dealing with primitive data. This is actual data, such as strings and numbers. This type of data is not too complex and is fairly easy for us to deal with. However, not all information is as simple as primitive data. Let's look at an example to clarify things a little.
Suppose you had written a web application that displayed timetable information for buses or trains. Once the user has selected a journey, you might want to let him know how long that journey will take. To do that, you would need to subtract the arrival time from the departure time.
However, that's not quite as simple as it may appear at first glance. For example, consider a departure time of 14:53 (for 2:53 p.m.) and an arrival time of 15:10 (for 3:10 p.m.). If we tell JavaScript to evaluate the expression 15.10–14.53, we get the result 0.57, which is 57 minutes. However, we know that the real difference in time is seventeen minutes. Using the normal mathematical operators on times doesn't work!
What would we need to do to calculate the difference between these two times? We would first need to separate out the hours from the minutes in each time. Then, to get the minutes difference between the two times, we would need to check whether the minutes of the arrival time were greater than the minutes of the departure. If so, we can simply subtract the departure time minutes from the arrival time minutes. If not, we need to add 60 to the arrival time minutes, and subtract one from the arrival time hours to compensate, before taking the departure time minutes from the arrival time minutes. We then need to subtract the departure time hours from the arrival time hours, before putting the minutes and hours that we have arrived at back together.
This would work OK, so long as the two times were in the same day. It wouldn't work, for example, with the times 23:45 and 04:32.
This way of working out the time difference obviously has its problems, but it also seems very complex. Is there an easier way to deal with more complex data such as times and dates?
This is where objects come in. We can define our departure and arrival times as Date objects. Because they are Date objects, they come with a variety of properties and methods that we can use when we need to manipulate or calculate with the times. For example, we can use the getTime() method to get the number of milliseconds between the time in the Date object and January 1, 1970, 00:00:00. Once we have these millisecond values for the arrival and departure times, we can simply subtract one from the other and store the result in another Date object. To retrieve the hours and minutes of this time, we simply use the getHours() and getMinutes() methods of the Date object. We'll see more examples of this later in the chapter.
The Date object is not the only object that JavaScript has to offer. Another object was introduced in Chapter 2, but to keep things simple, I didn't tell you it was an object at the time. That object was the Array object. Recall that an array is a way of holding a number of pieces of data at the same time.
Array objects have a property called length that tells us how many pieces of data, or rather how many elements, the array holds. We actually used this property in the Trivia Quiz in Chapter 3 to work out how many times we needed to loop through the array.
Array objects also have a number of methods. One example is the sort() method, which can be used to sort the elements within the array into alphabetical order.
You should now have an idea why objects are useful in JavaScript. We have seen the Date and Array objects, but there are many other objects that JavaScript makes available so that we can achieve more with our code. These include the Math and String objects, which we will talk more about later in the chapter.
Now that we have seen the "why" of JavaScript objects, we need to look at the "what" and the "how."
Each of the JavaScript objects has a collection of related properties and methods that can be used to manipulate a certain kind of data. For example, the Array object consists of methods to manipulate arrays and properties to find out information from them. In most cases, to make use of these methods and properties we need to define our data as one of these objects. In other words, we need to create an object.
In this section, we'll look at how we go about creating an object and, having done that, how we use its properties and methods.
We have already seen an example of an Array object being created. To create an Array object, we used the JavaScript statement
var myArray = new Array();
So how is this statement made up?
The first half of the statement is familiar to us. We use the var keyword to define a variable called myArray. This variable is initialized, using the assignment operator (=), to the right-hand side of the statement.
The right-hand side of the statement consists of two parts. First we have the keyword new. This tells JavaScript that we want to create a new object. Next we have Array(). This is the constructor for an Array object. It tells JavaScript what type of object we want to create. Most objects have constructors like this. For example, the Date object has the Date() constructor. The only exception we see in this book is the Math object, and this will be explained in a later part of the chapter.
We also saw in Chapter 2 that we can pass parameters to the constructor Array() to add data to our object. For example, to create an Array object that has three elements containing the data "Paul", "Paula", and "Pauline", we use
var myArray = new Array("Paul", "Paula", "Pauline");
Let's see some more examples, this time using the Date object. The simplest way of creating a Date object is
var myDate = new Date();
This will create a Date object containing the date and time that it was created. However,
var myDate = new Date("1 Jan 2000");
will create a Date object containing the date 1 January 2000.
How object data is stored in variables differs from how primitive data, such as text and numbers, is stored. (Primitive data is the most basic data possible in JavaScript.) With primitive data, the variable holds the data's actual value. For example
var myNumber = 23;
means that the variable myNumber will hold the data 23. However, variables assigned to objects don't hold the actual data, but rather a reference to the memory address where the data can be found. This doesn't mean we can get hold of the memory address—this is something only JavaScript has details of and keeps to itself in the background. All you need to remember is that when we say that a variable references an object, this is what we mean. We show this in the following example:
var myArrayRef = new Array(0, 1, 2); var mySecondArrayRef = myArrayRef; myArrayRef[0] = 100; alert(mySecondArrayRef[0]);
First we set variable myArrayRef reference to the new array object, and then we set mySecondArrayRef to the same reference—for example, now mySecondArrayRef is set to reference the same array object. So when we set the first element of the array to 100 as shown here:
myArrayRef [0] = 100;
and display the contents of the first element of the array referenced in mySecondArrayRef as follows:
alert(mySecondArrayRef[0])
we'll see it also magically has changed to 100! However, as we now know, it's not magic; it's because both variables referenced the same array object because when it comes to objects, it's a reference to the object and not the object stored in a variable. When we did the assignment, it didn't make a copy of the array object, it simply copied the reference. Contrast that with the following:
var myVariable = "ABC"; var mySecondVariable = myVariable; myVariable = "DEF"; alert(mySecondVariable);
In this case we're dealing with a string, which is primitive data type, as are numbers. This time it's the actual data that's stored in the variable, so when we do this:
var mySecondVariable = myVariable;
mySecondVariable gets its own separate copy of the data in myVariable. So the alert at the end will still show mySecondVariable as holding "ABC."
To summarize this section, we create a JavaScript object using the following basic syntax:
var myVariable = new ObjectName(optional parameters);
Accessing the values contained in an object's properties is very simple. We write the name of the variable containing (or referencing) our object, followed by a dot, and then the name of the object's property.
For example, if we defined an Array object contained in the variable myArray, we could access its length property using
myArray.length
This would give us the number of elements contained in the array.
But what can we do with this property now that we have it? We can use this property as we would any other piece of data and store it in a variable
var myVariable = myArray.length;
or show it to the user
alert(myArray.length);
In some cases, we can even change the value of the property, such as
myArray.length = 12;
However, unlike variables, some properties are read-only—we can get information from them, but we can't change information inside them.
Methods are very much like functions in that they can be used to perform useful tasks, such as getting the hours from a particular date or generating a random number for us. Again like functions, some methods return a value, such as the Date object's getHours() method, while others perform a task, but return no data, such as the Array object's sort() method.
Using the methods of an object is very similar to using properties in that you put the object's variable name first, then a dot, and then the name of the method. For example, to sort the elements of an Array in the variable myArray, you may use the following code:
myArray.sort();
Just like functions, you can pass parameters to some methods, where the parameters are placed between the parentheses following the method's name. However, whether or not a method takes parameters, we must still put parentheses after the method's name, just as we did with functions. As a general rule, anywhere you can use a function, you can use a method of an object.
You should now have a good idea about the difference between primitive data, such as numbers and strings, and object data, such as Dates and Arrays. However, I mentioned earlier that there is also a String object. Where does this fit in?
In fact there are String, Number, and Boolean objects corresponding to the three string, number, and Boolean primitive data types. For example, to create a String object containing the text "I'm a String object," we can use
var myString = new String("I'm a String object");
The String object has the length property just as the Array object does. This returns the number of characters in the String object. For example
var lengthOfString = myString.length;
would store the data 19 in the variable lengthOfString (remember that spaces are referred to as characters too).
But what if we had declared a primitive string called mySecondString holding the text "I'm a _primitive string" like this:
var mySecondString = "I'm a primitive string";
and wanted to know how many characters could be found in this primitive string?
This is where JavaScript helps us out. Recall from previous chapters that JavaScript can handle the conversion of one data type to another automatically. For example, if we tried to add a string primitive to a number primitive
theResult = "23" + 23;
JavaScript would assume that we want to treat the number as a string and concatenate the two together, the number being converted to text automatically. The variable theResult would contain "2323"—the concatenation of 23 and 23, and not the sum of 23 + 23, which is 46.
The same applies to objects. If we declare a primitive string and then treat it as an object, such as by trying to access one of its methods or properties, JavaScript would know that the operation we're trying to do won't work if it's a primitive string. It will only work if it's an object; for example, it would be valid if it were a String object. In this case, JavaScript converts the plain text string into a temporary String object, just for that operation.
So, for our primitive string mySecondString, we can use the length property of the String object to find out the number of characters it contains. For example
var lengthOfSecondString = mySecondString.length;
would store the data 22 in the variable lengthOfSecondString.
The same ideas we have expressed here are also true for number and Boolean primitives and their corresponding Number and Boolean objects. However, these objects are not used very often, so we will not be discussing them further in this book.