Полезная информация

Chapter 4

Functions and Objects-The Building Blocks of Programs


CONTENTS


Once you start to write more complex programs, you will quickly find the need to perform some tasks and actions more than once during the course of a program.

This need is addressed by functions, which are similar to methods but are not attached to any particular object. As a programmer, you can create numerous functions in your programs-this helps organize the structure of your applications and makes maintaining and changing your program code easier.

In addition, functions are particularly useful in working with events and event handlers as you will learn in Chapter 5, "Events in JavaScript."

You can also use functions as the basis for creating your own objects to supplement those available to you in JavaScript.

In this chapter we will cover these topics:

What Are Functions?

Functions offer the ability for programmers to group together program code that performs a specific task-or function-into a single unit that can be used repeatedly throughout a program.

Like the methods you have seen in earlier chapters, a function is defined by name and is invoked by using its name.

Also, like some of the methods you have seen before (such as prompt() and confirm()), functions can accept information in the form of arguments and can return results.

JavaScript includes several built-in functions as well as methods of base objects. You have already seen these when you used alert(), document.write(), parseInt(), or any of the other methods and functions you have been working with. The flexibility of JavaScript, though, lies in the ability for programmers to create their own functions to supplement those available in the JavaScript specification.

Using Functions

In order to make use of functions, you need to know how to define them, pass arguments to them, and return the results of their calculations. It is also important to understand the concept of variable scope, which governs whether a variable is available in an entire script or just within a specific function.

Defining Functions

Functions are defined using the function statement. The function statement requires a name for the function, a list of parameters-or arguments-that will be passed to the function, and a command block that defines what the function does:

function function_name(parameters, arguments) {
  command block
}

As you will notice, the naming of functions follows basically the same rules as variables: They are case sensitive, can include underscores (_), and start with a letter. The list of arguments passed to the function appears in parentheses and is separated by commas.

It is important to realize that defining a function does not execute the commands that make up the function. It is only when the function is called by name somewhere else in the script that the function is executed.

Passing Parameters

In the following function, you can see that printName() accepts one argument called name:

function printName(name) {
  document.write("<HR>Your Name is <B><I>");
  document.write(name);
  document.write("</B></I><HR>");
}

Within the function, references to name refer to the value passed to the function.

There are several points here to note:

For example, if you call printName() with the command:

printName("Bob");

then, when printName() executes, the value of name is "Bob". If you call printName() by using a variable for an argument:

var user = "John";
printName(user);

then name has the value "John". If you were to add a line to printName() changing the value of name:

name = "Mr. " + name;

name would change, but the variable user, which was sent as an argument, would not change.

Note
When passing arguments to a function, two properties that can be useful in working with the arguments are created: functionname.arguments and function.arguments.length. functionname.arguments is an array with an entry for each argument and functionname.argument.length is an integer variable indicating the number of variables passed to the function. You can use these properties to produce functions that accept a variable number of arguments.

Variable Scope

This leads to a discussion of variable scope. Variable scope refers to where a variable exists.

For instance, in the example printName(), name exists only within the function printName()-it cannot be referred to or manipulated outside the function. It comes into existence when the function is called and ceases to exist when the function ends. If the function is called again, a new instance of name is created.

In addition, any variable declared using the var command within the function will have a scope limited to the function.

If a variable is declared outside the body of a function, it is available throughout a script-inside all functions and elsewhere.

Variables declared within a function are known as local variables. Variables declared outside functions and available throughout the script are known as global variables.

If you declare a local variable inside a function that has the same name as an existing global variable, then inside the function, that variable name refers to the new local variable and not the global variable. If you change the value of the variable inside the function, it does not affect the value of the global variable.

Returning Results

As mentioned in the previous section, functions can return results. Results are returned using the return statement. The return statement can be used to return any valid expression that evaluates to a single value. For example, in the function cube(),

function cube(number) {
  var cube = number * number * number;
  return cube;
}

the return statement will return the value of the variable cube. This function could just as easily have been written like this:

function cube(number) {
  return number * number * number;
}

This works because the expression number * number * number evaluates to a single value.

Functions in the File Header

As was mentioned in Chapter 3, "Working with Data and Information," there are compelling reasons to include function definitions inside the HEAD tags of the HTML file.

This ensures that all functions have been parsed before it is possible for user events to invoke a function. This is especially relevant once you begin working with event handlers where incorrect placement of a function definition can mean an event can lead to a function call when the function has not been evaluated and Navigator doesn't know it exists. When this happens, it causes an error message to be displayed.

The term parsed refers to the process by which the JavaScript interpreter evaluates each line of script code and converts it into a pseudo-compiled Byte Code (much like Java), before attempting to execute it. At this time, syntax errors and other programming mistakes that would prevent the script from running may be caught and reported to the user or programmer.

The typeof Operator

JavaScript offers an operator that we didn't discuss in the last chapter when we looked at variables, expressions, and operators. The typeof operator is used to identify the type of an element in JavaScript. Given an unevaluated operand (such as a variable name or a function name), the typeof operator returns a string identifying the type of the operand.

For instance, suppose you have the following JavaScript code:

var question="What is 10 x 10?";
var answer=10;
var correct=false;
function showResult(results) {
   document.write(results);
}

Then, typeof question returns string; typeof answer returns number; typeof correct re-turns boolean; and typeof showResult returns function. Other possible results returned by the typeof operator include undefined and object.

Note
The typeof operator can be useful in determining if a function has been loaded and is ready to be called. This is especially useful in multi-frame pages where a script loaded in one frame might be trying to call a function located in another frame that hasn't completed loading.

Frames are covered in more detail in Chapter 8.

Putting Functions to Work

To demonstrate the use of functions, you are going to rewrite the simple test question example you used in Listing 3.3. In order to do this, you are going to create a function that receives a question as an argument, poses the question, checks the answer, and returns an output string based on the accuracy of the user's response as shown in Listing 4.1

In order to do this, you need to learn the eval() method, which evaluates a string to a numeric value; for instance,

eval("10*10")

returns a numeric value of 100.


Listing 4.1. Evaluating an expression with the eval() function.
<HTML>

<HEAD>
<TITLE>Example 4.1</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//DEFINE FUncTION testQuestion()
function testQuestion(question) {
  //DEFINE LOCAL VARIABLES FOR THE FUncTION
  var answer=eval(question);
  var output="What is " + question + "?";
  var correct='<IMG SRC="correct.gif">';
  var incorrect='<IMG SRC="incorrect.gif">';

  //ASK THE QUESTION
  var response=prompt(output,"0");

  //chECK THE RESULT
  return (response == answer) ? correct : incorrect;
}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD<

<BODY>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//ASK QUESTION AND OUTPUT RESULTS
var result=testQuestion("10 + 10");
document.write(result);

//STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</BODY>

</HTML>

At first glance, this script may seem a little more complicated than the version used in Listing 3.3. In reality, though, it simply separates the work into logical blocks and moves most of the work into the function testQuestion().

To understand the function, let's analyze the key lines.

function testQuestion(question) {

In this line, you define the function testQuestion() and indicate that it receives one argument, which is referred to as question within the function. In the case of this function, it is expected that question will be a string containing an arithmetic expression.

var answer=eval(question);

The first thing you do after entering the function is to declare the variable answer and assign to it the numeric value of the arithmetic expression contained in the string question. This is achieved using the eval() function.

  var output="What is " + question + "?";
  var correct='<IMG SRC="correct.gif">';
  var incorrect='<IMG SRC="incorrect.gif">';

In these lines you declare several more variables. The variable output contains the actual question to display, which is created using the concatenation operator.

var response=prompt(output,"0");

Here you ask the question and assign the user's response to the variable response.

return (response == answer) ? correct : incorrect;

In this line you use the conditional operator to check the user's response. The resulting value is returned by the return command.

Now that you understand the function, it should be clear how you are invoking it later in the body of the HTML file. The line

var result=testQuestion("10 + 10");

calls testQuestion() and passes a string to it containing an arithmetic expression. The function returns a result, which is stored in the variable result. Then you are able to output the result using document.write().

These two lines could be condensed into a single line:

document.write(testQuestion("10 + 10"));

Recursive Functions

Now that you have seen an example of how functions work, let's take a look at an application of functions called recursion.

Recursion refers to situations in which functions call themselves. These types of functions are known as recursive functions.

For instance, the following is an example of a recursive function that calculates a factorial:

Note
A factorial is a mathematical function. For example, factorial 5 (written 5!) is equal to 5×4×3×2×1 and 7! = 7×6×5×4×3×2×1.

function factorial(number) {
  if (number > 1) {
    return number * factorial(number - 1);
  } else {
    return number;
  }
}

At first glance, this function may seem strange. This function relies on the fact that the factorial of a number is equal to the number multiplied by the factorial of one less than the number. Expressed mathematically, this could be written:

x! = x * (x-1)!

In order to apply this formula, you have created a recursive function called factorial(). The function receives a number as an argument. Using the following if-else construct:

if (number > 1) {
  return number * factorial(number - 1);
} else {
  return number;
}

The function either returns a value of 1 if the argument is equal to 1 or applies the formula and returns the number multiplied by the factorial of one less than the number.

In order to do this, it must call the function factorial() from within the function factorial(). This is where the concept of variable scope becomes extremely important. It is important to realize that when the function calls factorial(), a new instance of the function is being invoked, which means that a new instance of number is created. This continues to occur until the expression number-1 has a value of 1.

Tip
Recursive functions are powerful, but they can be dangerous if you don't watch out for infinite recursion. Infinite recursion occurs when the function is designed in such a way as to call itself forever without stopping.
At a practical level, in JavaScript, infinite recursion isn't likely to happen because of the way in which JavaScript handles some of its memory allocation. This means that deep recursions, even if they aren't infinite, may cause Navigator to crash.

It is important to note that the function factorial() prevents infinite recursion because the if-else construct ensures that eventually the function will stop calling itself once the number passed to it is equal to one. In addition, if the function is initially called with a value less than two, the function will immediately return without any recursion.

Using recursive functions, it is possible to extend the program used in Listing 4.1 so that it continues to ask the question until the user provides the correct answer, as shown in
Listing 4.2.


Listing 4.2. Using a recursive function to repeat input.
<HTML>

<HEAD>
<TITLE>Example 4.2</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//DEFINE FUncTION testQuestion()
function testQuestion(question) {
  //DEFINE LOCAL VARIABLES FOR THE FUncTION
  var answer=eval(question);
  var output="What is " + question + "?";
  var correct='<IMG SRC="correct.gif">';
  var incorrect='<IMG SRC="incorrect.gif">';

  //ASK THE QUESTION
  var response=prompt(output,"0");

  //chECK THE RESULT
  return (response == answer) ? correct : testQuestion(question);
}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD<

<BODY>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//ASK QUESTION AND OUTPUT RESULTS
var result=testQuestion("10 + 10");
document.write(result);

//STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</BODY>

</HTML>

Notice that you have made only a single change to the conditional expression:

return (response == answer) ? correct : testQuestion(question);

Where you originally returned the value of the variable incorrect when the user provided an incorrect response, you are now returning the result of asking the question again (by calling testQuestion() again).

It is important to realize that this example could cause JavaScript to crash because of its memory handling problems if the user never provides the correct answer. This can be remedied by adding a counter to keep track of the number of chances the user has to provide a correct answer:

<HTML>

<HEAD>
<TITLE>Example 4.2</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//DEFINE FUncTION testQuestion()
function testQuestion(question,chances) {
  //DEFINE LOCAL VARIABLES FOR THE FUncTION
  var answer=eval(question);
  var output="What is " + question + "?";
  var correct='<IMG SRC="correct.gif">';
  var incorrect='<IMG SRC="incorrect.gif">';

  //ASK THE QUESTION
  var response=prompt(output,"0");

  //chECK THE RESULT
  if (chances > 1) {
    return (response == answer) ? correct : testQuestion(question,chances-1);
  } else {
    return (response == answer) ? correct : incorrect;
  }
}

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD<

<BODY>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//ASK QUESTION AND OUTPUT RESULTS
var result=testQuestion("10 + 10",3);
document.write(result);

//STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</BODY>

</HTML>

By adding the if-else construct when you check the user's answer, you are ensuring that you cannot enter an infinite recursion. The if-else construct could be replaced by a conditional expression:

return (response == answer) ? correct : ((chances > 1) ?
testQuestion(question,chances-1) : incorrect);

What this expression says is, if the user's response is correct (response==answer evaluates to true), then return the value of correct. Otherwise, if there are chances left (chances > 1 evaluates to true), ask the question again and return the result. If there are no chances left and the answer is incorrect, return the value of the variable incorrect.

Building Objects in JavaScript

As you learned earlier, it is possible to use functions to build custom objects in JavaScript. In order to do this, you must be able to define an object's properties, to create new instances of objects, and to add methods to objects.

Defining an Object's Properties

Before creating a new object, it is necessary to define that object by outlining its properties. This is done by using a function that defines the name and properties of the function.

This type of function is known as a constructor function.

If you want to create an object type for students in a class, you could create an object named student with properties for name, age, and grade. This could be done with the function:

function student(name,age, grade) {
  this.name = name;
  this.age = age;
  this.grade = grade;
}

Note
Notice the use of the special keyword this. this plays a special role in JavaScript and refers to the current object. You will learn more about this in Chapter 5, when we begin discussing event handlers.

Using this function, it is now possible to create an object using the new statement:

student1 = new student("Bob",10,75);

This line of JavaScript code creates an object called student1 with three properties: student1.name, student1.age, and student1.grade. This is known as an instance of the object student. By creating a new object student2 using the new statement,

student2 = new student("Jane",9,82);

you would be creating a new instance of the object that is independent from student1.

It is also possible to add properties to objects once they are created simply by assigning values to a new property. For instance, if you want to add a property containing Bob's mother's name, you could use the structure

student1.mother = "Susan";

This would add the property to student1 but would have no effect on student2 or future instances of the student object. To add the property mother to all instances of student, it would be necessary to add the property to the object definition before creating instances of the object:

function student(name, age, grade, mother) {
  this.name = name;
  this.age = age;
  this.grade = grade;
  this.mother = mother;
}

Objects as Properties of Objects

You can also use objects as properties of other objects. For instance, if you were to create an object called grade

function grade (math, english, science) {
  this.math = math;
  this.english = english;
  this.science = science;
}

you could then create two instances of the grade object for the two students:

bobGrade = new grade(75,80,77);
janeGrade = new grade(82,88,75);

Note
The order of arguments is important in JavaScript. In the preceding example, if Jane hasn't taken English, you would need to pass a place-holder to the function, such as zero or a string value, such as "N/A" or the empty string. The function would then need to be written to handle this eventuality.

Using these objects, you could then create the student objects like this:

student1 = new student("Bob",10,bobGrade);
student2 = new student("Jane",9,janeGrade);

You could then refer to Bob's math grade as student1.grade.math or Jane's science grade as student2.grade.science.

Adding Methods to Objects

In addition to adding properties to object definitions, you can also add a method to an object definition. Because methods are essentially functions associated with an object, first you need to create a function that defines the method you want to add to your object definition.

For instance, if you want to add a method to the student object to print the student's name, age, and grades to the document window, you could create a function called displayProfile():

function displayProfile() {
  document.write("Name: " + this.name + "<BR>");
  document.write("Age: " + this.age + "<BR>");
  document.write("Mother's Name: " + this.mother + "<BR>");
  document.write("Math Grade: " + this.grade.math + "<BR>");
  document.write("English Grade: " + this.grade.english + "<BR>");
  document.write("Science Grade: " + this.grade.science + "<BR>");
}

Note
Here again, you use this to refer to the object that is invoking the method. If you call a method as object1.method, then this refers to object1.

Having defined the method, you now need to change the object definition to include the method:

function student(name,age, grade) {
  this.name = name;
  this.age = age;
  this.grade = grade;
  this.mother = mother;
  this.displayProfile = displayProfile;
}

Then, you could output Bob's student profile by using the command:

student1.displayProfile();

This would produce results similar to those in Figure 4.1.

Figure 4.1 : The display. Profile() method displays the profile for any instance of the student object.

Extending Objects Dynamically

Starting with Navigator 3.0, it is possible to extend objects after they have been created with a new statement.

Properties can be added to object definitions by setting the value of objectName.prototype.propertyName. objectName refers to the name of the constructor function, and propertyName is the name of the property or method being added to the function.

For instance, if you want to add an additional method called updateProfile() to the student object definition you created earlier, you could use the command:

student.prototype.updateProfile = updateInfo;

where you have already created a function called updateInfo():

function updateInfo() {
   this.age = prompt("Enter the correct age for " + this.name,this.age);
   this.mother = prompt("Enter the mother's name for " + this.name,this.mother);
}

Then, all instances of student that had previously been created using the new statement would be able to use the new method.

In the example we used above, you could update the age and mother's name for Bob by using this command:

student1.updateProfile();

Defining Your Own Objects

To further demonstrate the application of objects and defining your own objects, Listing 4.3 is a program that asks the user for personnel information of an employee and then formats it for display on the screen.

In order to do this, you need to define an employee object, as well as a method for displaying the employee information.


Listing 4.3. Creating an employee profile.
<HTML>

<HEAD>
<TITLE>Example 4.3</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//DEFINE METHOD
function displayInfo() {
  document.write("<H1>Employee Profile: " + this.name + "</H1><HR><PRE>");
  document.writeln("Employee Number: " + this.number);
  document.writeln("Social Security Number: " + this.socsec);
  document.writeln("Annual Salary: " + this.salary);
  document.write("</PRE>");
}

//DEFINE OBJECT
function employee() {
  this.name=prompt("Enter Employee's Name","Name");
  this.number=prompt("Enter Employee Number for " + this.name,"000-000");
  this.socsec=prompt("Enter Social Security Number for " +
this.name,"000-00-0000");
  this.salary=prompt("Enter Annual Salary for " + this.name,"$00,000");
  this.displayInfo=displayInfo;
}

newEmployee=new employee();

// STOP HIDING  FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

newEmployee.displayInfo();

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</BODY>

</HTML>

This script produces results similar to those in Figure 4.2 and 4.3.

Figure 4.2 :The program prompts the user for the employee information.

Figure 4.3 : The method you defined displays the formatted data.

In this example, the most noticeable variation on what you have learned is that you don't pass any arguments to the object definition function, employee().

Instead, this object definition is more of a dynamic object definition in that, when a new instance of the object is created, the user is prompted for all the relevant data for the properties.

Properties as Indexes

In Navigator 2.0, it was possible to refer to object properties numerically in two ways other than objectName.propertyName. That is, in the previous example of the student object, the properties of student2 could have been referred to as:

student2["name"]
student2["age"]

and so on, or by numbers starting at zero, where

student2[0] == "Jane"
student2[1] == 9

This use of the names and numbers is known as indexes.

In Navigator 3.0, it is no longer possible to refer to a property both by numeric index and by name. Instead, properties can either be created as numeric indexes or names but then
all subsequent references have to be the same. Numbers and names cannot be used inter-changeably.

Arrays

Anyone who has programmed in other structured languages has probably encountered arrays of one sort or another and will be wondering where JavaScript's arrays are.

Arrays are ordered collections of values referred to by a single variable name. For instance, if you have an array named student, you might have the following ordered values:

student[0] = "Bob"
student[1] = 10
student[2] = 75

Array elements are referred to by their indexes-the numbers in brackets. In JavaScript, arrays start with index zero.

Arrays in JavaScript are created using the Array() constructor object. You can create an array of undefined length by using the r">new keyword:

arrayName = new Array();

The length of the array changes dynamically as you assign values to the array. The length of the array is defined by the largest index number used.

For instance

var sampleArray = new Array();
sampleArray[49] = "50th Element";

creates an array with 50 elements. (Remember, indexes start at zero.)

It is also possible to define an initial length of an array by passing the length to the Array() object as an argument:

var sampleArray = new Array(100);

In addition, you can create an array and assign values to all its elements at the time it is defined. This is done by passing the value for all elements as arguments to the Array() object. For instance,

var sampleArray = new Array("1st Element", 2, "3rd Element);

creates a three-element array with the values

sampleArray[0] == "1st Element"
sampleArray[1] == 2
sampleArray[2] == "3rd Element"

As objects, arrays have several methods, including

To demonstrate how arrays can be useful, Listing 4.4 builds on the personnel information example in the Listing 4.3.

In this example, you do not have the user enter the personnel information for the new employee in the same way. You present a list of information you want. The users select a number for the information they want to enter. When they are done, they select "0."

After a user finishes entering the information, the script displays the formatted employee profile.


Listing 4.4. Creating a user menu.
<HTML>

<HEAD>
<TITLE>Listing 4.4</TITLE>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

//DEFINE METHOD
function displayInfo() {
  document.write("<H1>Employee Profile: " + this.data[0] + "</H1><HR><PRE>");
  document.writeln("Employee Number: " + this.data[1]);
  document.writeln("Social Security Number: " + this.data[2]);
  document.writeln("Annual Salary: " + this.data[3]);
  document.write("</PRE>");
}

//DEFINE METHOD TO GET EMPLOYEE INFORMATION
function getInfo() {
  var menu="0-Exit/1-Name/2-Emp. #/3-Soc. Sec. #/4-Salary";
  var choice=prompt(menu,"0");
  if (choice != null) {
    if ((choice < 0) || (choice > 4)) {
      alert ("Invalid choice");
      this.getInfo();
    } else {
      if (choice != "0") {
        this.data[choice-1]=prompt("Enter information","");
        this.getInfo();
      }
    }
  }
}

//DEFINE OBJECT
function employee() {
  this.data = new Array(4);
  this.displayInfo=displayInfo;
  this.getInfo=getInfo;
}

newEmployee=new employee();

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</HEAD>

<BODY>

<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE FROM OTHER BROWSERS

newEmployee.getInfo();
newEmployee.displayInfo();

// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>

</BODY>

</HTML>

This script produces a series of results similar to those in Figures 4.4, 4.5, and 4.6.

Figure 4.4 : A menu in a prompt box.

Figure 4.5 : Prompting for input

Figure 4.6 : The final result.

In this example, you can see several of the concepts you have learned in action here, including recursion and arrays.

The method getInfo() needs some explanation:

var menu="0-Exit/1-Name/2-Emp. #/3-Soc. Sec. #/4-Salary";

The menu variable contains the string that presents the choices to the user. Notice the use of the \n special character to create a multiline menu in a single text string.

  var choice = prompt(menu,"0");

Here you present the menu to the user and ask for a choice, which is stored in the variable choice.

if (choice != null) {
    if ((choice < 0) || (choice > 4)) {
      alert ("Invalid choice");
      this.getInfo();
    } else {
      if (choice != "0") {
        this.data.[choice-1]=prompt("Enter information","");
        this.getInfo();
      }
    }
  }

This set of if statements is where the real work of the getInfo() method is done. The first if statement checks whether the user has selected Cancel. If not, then the user's choice is checked to make sure it is in range (from zero to four). If the choice is out of range, then the user is alerted, and the getInfo() method is called again. If the user's choice is in range, it is checked to see if the user has chosen 0 for exit. If the user doesn't select 0, the user is prompted to enter the data he has indicated. Then the getInfo() method is called again to present the menu again.

You will notice the use of the this keyword to refer to the current object and the use of this data [choice-1] to refer to the array element (or property) selected by the user. You use choice-1 because the menu presents choices from 1 to 4 to the user, but array indexes start from 0 and, in this case, the index goes up to 3.

Functions as Objects

Functions in JavaScript can be created as instances of the special Function object using the new keyword:

functionName = new Function(arglist, functionDefinition);

This provides an alternate way to create functions. In the example above, arglist is a comma-separated list of argument names, and functionDefinition is the JavaScript code to be executed each time the function is called. Each item in the argument list should be a string literal.

Functions defined using the Function object can be used in the same way as functions defined using the function keyword (including in event handlers) and can be called directly in expressions.

Instances of the Function object have two properties:

According to the Netscape documentation, creating functions using the Function object is the less efficient of the two methods of creating objects.

Summary

Functions provide a means to define segments of code that can be used more than once in a program. Like methods, which are part of objects, functions are defined by names, can be passed arguments, and can return results.

Variable scope, whether a variable exists locally to a function or globally for the entire program, is an important concept in dealing with functions.

Recursive functions are functions that call themselves one or more times. Recursion is a powerful tool, but it needs to be used carefully to avoid infinite recursion, which occurs when a function repeatedly calls itself without ever ending. With the current implementation of JavaScript, infinite recursion can't really happen because memory handling shortcomings mean that Navigator will crash when recursion gets too deep.

Functions are also used to define the properties and objects that make up user-defined methods. Using the new keyword, it is possible to create multiple instances of an object which all exist independently.

Arrays provide a mechanism to group together data into ordered collections. Index numbers provide a means to access individual elements in an array.

If you have made it to the end of this chapter, you are making progress because recursion, functions, and objects are advanced topics.

In Chapter 5, you begin to work with events and event handlers which will allow you to design programs that interact with the user in a sophisticated way.

Commands and Extensions Review

Command/ExtensionType Description
function JavaScript keywordDeclares a function
new JavaScript keywordCreates a new instance of an object
eval() JavaScript methodEvaluates a string to a numeric value
this JavaScript keywordRefers to the current object
type of JavaScript operatorReturns a string indicating the type of the operand

Exercises

  1. Write the object definition for an object called car with four properties: model, make, year, and price.
  2. If you have an object defined as follows

    function house(address,rooms,owner) {
      this.address = address;
      this.rooms = rooms;
      this.owner = owner;
    }

    and you create two instances of the house object

    house1 = new house("10 Maple St.",10,"John");
    house2 = new house("15 Sugar Rd.",12,"Mary");

    then, what would be the value of the following:

    a.  house1.rooms
    b.  house2.owner
    c.  house1["address"]
  3. Create a function that calculates the value of x to the power of y. For instance, if you have a function called power() and you issue the command

    value = power(10,4);

    then power() should return the value of 10 to the power of 4, or 10 * 10 * 10 * 10.

Note
If the notation x^y refers to x to the power of y, then it will be helpful in writing this function to realize that x^y = x * x^(y-1).

Answers

  1. The object definition would look like this:

    function car(model, make, year, price) {
      this.model = model;
      this.make = make;
      this.year = year;
      this.price = price;
    }
  2. The values are as follows:
    a.  10
    b.  "Mary"
    c.  "10 Maple St."
  3. The power() function could be written using recursion:
    function power(number, exponent) {
      if (exponent > 1) {
        return number * power(number, exponent - 1);
      } else {
        return 1;
      }
    }

    This function makes use of a similar principle as the factorial example earlier in the chapter. This function uses the fact that x to the power of y equals x multiplied by x to the power of y-1.
    While this function works, it is important to note that it isn't perfect. Although negative exponents are mathematically legal, this function will not calculate the result correctly for this type of exponent.
    Remembering that x to the power of -y is the same as 1 divided by x to the power of y, you could fix the problem with negative exponents by making the following change to the function:

    function power(number, exponent) {

      // chECK IF WE HAVE A NEGATIVE EXPONENT
      var negative = (exponent < 0) ? true : false;

      // DECLARE WORKING VARIABLE
      var value=0;

      // CALCULATE number TO THE POWER OF exponent
      if (exponent > 1) {
        value = number * power(number, exponent - 1);
      } else {
        value = 1;
      }

      // IF THE EXPONENT WAS NEGATIVE, TAKE THE RECIPROCAL
      if (negative)
        value = 1 / value;

      return value;
    }

Note
JavaScript includes a method that performs the same operation as your power() function. The Math.pow() method is part of the Math object and is discussed in Chapter 10, "Strings, Math, and the History List."