Chapter 8. Custom Objects

The built-in objects discussed in Lesson 7 go a long way in making applications easier to write and maintain, but they stop short of allowing developers to tailor objects to their personal needs and those of their applications. For example, what if it were your job to write an application that emulates a two-dimensional Cartesian coordinate plane? How would the Array, Date, Number, and String data types help you achieve that goal? It could be done, but it would take a lot of time and effort to write a proper application.

The fact is that JavaScript or any object-oriented programming language for that matter wouldn't be useful without the capability to create objects other than the built-in objects provided by the language. Being able to build your own objects and data types makes it possible to write flexible and maintainable applications.

At the heart of JavaScript's object-oriented design is the Object data type. It's the basis of all objects and reference types in JavaScript, and you'll look at how to use it in this lesson.

THE OBJECT DATA TYPE

There are two ways to create a basic object. The first is to use the Object data type's constructor, like this:

var coordinates = new Object();

This code calls the Object() constructor using the new keyword and assigns it to the coordinates variable. As with the Array data type, there is a much simpler (and preferred) way to create an object, by using object literal notation:

var coordinates = {};

Object literal notation uses curly braces as opposed to the square braces used to denote an array literal.

A plain object isn't usable. There's not much you can do with one, but JavaScript is a dynamic language. You can add properties to objects on-the-fly. All you need to do is assign a value to a property, like this:

var coordinates = {};
coordinates.x = 0;
coordinates.y = 0;

It's possible to take this code a step further and define the object and its properties in one statement. Doing so produces something like the following code:

var coordinates = {
    x : 0,
    y : 0
};

This statement starts like any other assignment statement. The var keyword denotes a variable declaration or initialization, followed by the variable's identifier (coordinates in this case), and then the assignment operator. Next is an opening curly brace denoting an object literal, but then things start looking different.

Inside the curly braces is a list of property definitions separated by commas. Property definitions inside an object literal consist of the property's name, a colon (:), and then the property's value. Each definition is separated from the next by a comma; otherwise JavaScript wouldn't know where one property definition ends and another begins. In this code two properties are defined for the coordinates object. They are x and y, and this code assigns them both a value of 0.

After an object and its properties are defined, you can use them as you would any other object. Look at the following code:

var text = "X is " + coordinates.x + " and Y is " + coordinates.y;
alert(text);

The x and y properties of the coordinates object are concatenated with other string values. The final result is assigned to the text variable, and the second statement displays the contents of text to the user. This functionality would work well as a method, so let's add a method that performs this action to the coordinates object.

Method definitions follow the same principles as property definitions; the only difference is that the value to the right of the colon is a function. The following bolded code adds a method definition to the coordinates object:

var coordinates = {
    x : 0,
    y : 0,
    sayCoordinates : function() {
        var text = "X is " + this.x + " and Y is " + this.y;
        alert(text);
    }
};

First, notice that a comma was added to the end of y's definition. Since it is no longer the last member in the definition list, it needs a comma to separate it from the definition of sayCoordinates(). The code within the new method's body is very similar to the code in the previous example. But there's one change: A new keyword, called this, is used where the coordinates identifier was previously used. The this keyword is a special variable used inside a function; it points to the object on which the function is invoked as a method. The sayCoordinates() method is a member of coordinates. As such, it executes within the context of the coordinates object. Because of this, the this variable points to the coordinates object. The context in which this is used can easily be translated into spoken language. A statement like this.x = 0; translates to "Set the x property of this object to 0." When you see this, think "this object."

Outputting Objects

Custom objects have many uses in JavaScript development, but they're primarily used for data exchange. To continue the Cartesian plane example, a single point in 2D space must have two pieces of information: the x, or horizontal, information, and the y, or vertical, information. In order for the application to know where the current point is in 2D space, a function called getCurrentPoint() needs to return the x and y coordinates for the current point. JavaScript does not have a data type that represents coordinate data, but as you've seen in this lesson, a custom object can do it easily. The following code shows an example of what such a function might look like:

function getCurrentPoint() {
    // set initial values for current coordinates
    var currentX = 0;
    var currentY = 0;

    // code here to get the current x and y
    // and assign it to the variables

    return {
        x : currentX,
        y : currentY
    };
}

This function first initializes two local variables called currentX and currentY with a value of 0. Then, as stated by the comments, some code determines the x and y data and assigns the appropriate values to the currentX and currentY variables. Finally, the function returns an object, created with object literal notation, with two properties, x and y, that contain the values needed for the current point. Notice that this object has no identifier, and is not assigned to any local variable within the function. This code demonstrates how you can return any type of data without specifically creating and assigning it to a variable first.

To use this function, you might write code similar to this:

var point = getCurrentPoint();

alert(point.x);
alert(point.y);

The first line calls the getCurrentPoint() function and assigns the resulting value to the point variable, which is now an object. The next two lines of code show the point object in use by accessing the x and y properties.

Objects as Input

Just as returning an object to represent complex data is beneficial, so too is accepting objects as arguments in functions. Your fictional Cartesian plane application needs to draw a dot at a specific point on the graph, and a function called drawPoint() provides this ability for the application. The function might look like the following:

function drawPoint(x, y) {
    // do something with x
    // do something with y
}

Here, a traditional function accepts two arguments, and it performs some type of work with those arguments to draw a point on the screen. There's nothing wrong with this function, but it could fit better in an object-oriented environment by accepting an object containing coordinate data as an argument:

function drawPoint(point) {
    // do something with point.x
    // do something with point.y
}

var point = getCurrentPoint(); // get coordinates
drawPoint(point); // draw the dot on the screen

By means of a simple change, this function fits very well into an object-based environment. It's much easier to call since it now accepts one argument containing complex data.

CREATING CUSTOM DATA TYPES

Custom objects have their uses, but if you plan on using multiple objects that have the same properties and methods, a better solution is to write a custom data type that allows you to create objects using the new keyword and constructor functions.

The first step in creating a custom data type is to create the constructor function. Constructor functions closely resemble regular functions, except you define the data type's members inside the function. Constructor functions, by convention, begin with an uppercase letter. This is to help distinguish constructor functions from regular functions. The following code creates a data type called Point:

function Point(x, y) {
    this.x = x;
    this.y = y;
    this.getDistance = function(point) {
var x2 = Math.pow(point.x - this.x, 2);
        var y2 = Math.pow(point.y - this.y, 2);

        return Math.sqrt(x2 + y2);
    };
}

This Point constructor accepts two arguments, x and y coordinates. It accepts individual pieces of data, as opposed to the single object shown at the end of the previous section. This is a personal choice: The philosophy behind it is that individual pieces of data are combined to construct a singular complex piece of data. It would be perfectly fine for the constructor function to accept a custom object containing x and y properties.

Inside the constructor function two properties, x and y, are assigned the values passed to the constructor function. Notice the use of the this variable. Remember that this refers to the current object, and the current object, in this case, is the object being created by the calling of the Point() constructor function with the new keyword. So the first two statements in the constructor create x and y properties by assigning their values. If this were omitted and var were used in its place, x and y would simply be variables.

After creating the x and y properties, the constructor function creates a method called getDistance(). This method accepts a Point object as an argument, and it uses the Math object to work out the Euclidean distance formula to determine the distance between the point represented by the current object and the Point object passed to the method.

To create a Point object, simply call the constructor by using the new keyword, and pass it some data, like this:

var point1 = new Point(0, 0);
var point2 = new Point(1, 1);

With more than one Point object created, you can determine the distance between the two points by calling the getDistance() method on one of the objects and passing the other as an argument, like this:

var distance = point1.getDistance(point2);

When calling a constructor you create, it is very, very important to remember to include the new keyword. Not doing so results in near-catastrophic circumstances. Custom constructor functions use the special this variable to create properties and methods for the object the constructor function is making. If the new keyword is omitted, the this variable points to the global object.

Because of this, the constructor function creates the properties and methods defined within it on the global object. Not only is the global object polluted with properties and methods it doesn't need, but a new object is not created. There is no warning or error given by JavaScript; it simply executes the code. The only clue you have is that your code will not work as expected. So always, always remember to use the new keyword when calling a constructor function.

TRY IT

In this lesson, you learn how to create your own objects and use them in your code.

Lesson Requirements

For this lesson, you need a text editor; any plain text editor will do. For Microsoft Windows users, Notepad is available by default on your system or you can download Microsoft's free Visual Web Developer Express (www.microsoft.com/express/web/) or Web Matrix (www.asp.net/webmatrix/). Mac OS X users can use TextMate, which comes as part of OS X, or they can download a trial for Coda (www.panic.com/coda/). Linux users can use the built-in VIM.

You also need a modern web browser. Choose any of the following:

  • Internet Explorer 8+

  • Google Chrome

  • Firefox 3.5+

  • Apple Safari 4+

  • Opera 10+

Create a subfolder called Lesson08 in the JS24Hour folder you created in Lesson 1. Store the files you create in this lesson in the Lesson08 folder.

Step-by-Step

Write a Person data type that has two properties: firstName and lastName. It should also have a method called getFullName() to concatenate the two properties together and return the result of that concatenation, and a method to greet other Person objects.

  1. Open your text editor and type the following function:

    function Person(firstName, lastName) {
    
    }

    This is the basis of the constructor function for your Person data type. The function has two parameters: firstName and lastName.

  2. Now add the following bolded code:

    function Person(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    This code adds the firstName and lastName properties to the data type. Their values come from the values passed to the constructor.

  3. Add the following bolded code:

    function Person(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.getFullName = function() {
            return this.firstName + " " + this.lastName;
        };
    }

    This code adds the getFullName() method. It concatenates the firstName and lastName properties and returns the result of that operation. The result of the concatenation is not stored in a variable; it is directly returned to the caller.

  4. Now it's time to add the greet() method. It's bolded in the following code:

    function Person(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.getFullName = function() {
            return this.firstName + " " + this.lastName;
        };
    
        this.greet = function(person) {
            alert("Hello, " + person.getFullName());
        };
    }

    The greet() method accepts a Person object as an argument, and it calls the getFullName() method on that Person object to get the person's name and use it in a greeting message. The message is displayed in an alert window.

  5. Once again, add the bolded code that follows. Feel free to pass your own name to one of the constructor calls.

    function Person(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.getFullName = function() {
            return this.firstName + " " + this.lastName;
        };
    
        this.greet = function(person) {
            alert("Hello, " + person.getFullName());
        };
    }
    
    var person1 = new Person("Jeremy", "McPeak");
    var person2 = new Person("John", "Doe");
    
    person1.greet(person2);
  6. Save the file as lesson08_sample01.js.

  7. Open another instance of your text editor, type the following HTML, and save it as lesson08_sample01.htm:

    <html>
    <head>
        <title>Lesson 8: Custom Objects</title>
    </head>
    <body>
        <script type="text/javascript" src="lesson08_sample01.js"></script>
    </body>
    </html>
  8. Open the HTML file in your browser. An alert window displays the result of calling person.getFullName(): a string containing the values passed to the Person() constructor.

Note

Please select Lesson 8 on the DVD to view the video that accompanies this lesson. You can also download the sample code for all lessons from the book's website at www.wrox.com.

Step-by-Step
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.41.205