|
|||
|
Click Here! |
Chapter 4Functions 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 FunctionsIn 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 FunctionsFunctions 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) { 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 ParametersIn the following function, you can see that printName() accepts one argument called name: function printName(name) { 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"; 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.
Variable ScopeThis 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.
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 ResultsAs 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) { 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) { This works because the expression number * number * number evaluates to a single value. Functions in the File HeaderAs 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 typeof OperatorJavaScript 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?";
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.
Frames are covered in more detail in Chapter 8. Putting Functions to WorkTo 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>
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 + "?"; 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.
For instance, the following is an example of a recursive function
that calculates a factorial:
function factorial(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) { 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.
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. Using a recursive function to repeat input. <HTML>
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> 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) ? 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 JavaScriptAs 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.
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) {
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) { Objects as Properties of ObjectsYou 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) { you could then create two instances of the grade object for the two students: bobGrade = new grade(75,80,77);
Using these objects, you could then create the student objects like this: student1 = new student("Bob",10,bobGrade); 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 ObjectsIn 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() {
Having defined the method, you now need to change the object definition to include the method: function student(name,age, grade) { 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. Extending Objects DynamicallyStarting 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() { 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 ObjectsTo 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>
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.
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 IndexesIn 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"] and so on, or by numbers starting at zero, where student2[0] == "Jane"
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 ArraysAnyone 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" 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(); 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" 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>
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.
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) { 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 ObjectsFunctions 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. SummaryFunctions 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/Extension | Type | Description |
function | JavaScript keyword | Declares a function |
new | JavaScript keyword | Creates a new instance of an object |
eval() | JavaScript method | Evaluates a string to a numeric value |
this | JavaScript keyword | Refers to the current object |
type of | JavaScript operator | Returns a string indicating the type of the operand |
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). |
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." |
Use of this site is subject certain Terms & Conditions. Copyright (c) 1996-1999 EarthWeb, Inc.. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Please read our privacy policy for details. |