Functions and Statements in JavaScript
- Week 1: Day 3: Functions and Statements
- Predefined Global Functions
- What Is a Statement?
- Control Statements
- Loop Statements
- Summary
- Workshop
Week 1: Day 3: Functions and Statements
This chapter begins by looking at how you can store code by creating your own functions, and how you can control the flow of a script. This will provide the other "half" of the basics you will need to create useful scripts (in addition to what you learned about variables in Chapter 2, "Working with Data"). You will also find out about some of the conveniently built-in pieces of code found in JavaScript.
In this chapter you will learn the following:
-
What functions are
-
How to create a function
-
How to use a function
-
About predefined global functions
-
What statements are
-
Conditional statements
-
Loop statements
User Defined Functions
A user-defined function is a function that you create, as opposed to one of the built-in JavaScript functions. JavaScript provides both built-in functions and the tools to create your own. Both have their place, but for the moment, let's concentrate on learning what functions are and how we can build and use our own.
What Is a Function?
Chapter 2 started by looking at how variables and constants can be used to store data until it is needed or it can be used again. Although this is an essential part of programming, to create truly useful scripts you also need to be able to store code (as opposed to data). So far, the code we have worked with runs as soon as the page loads or is reloaded. Frequently, though, you may want to use the same piece of code multiple times or run it some time after the page has loaded in response to a user action. To do this, a function is used. Just as you can think of variables as data containers that can be used to store data, think of functions as code containers used to store pieces of code. Let's take a look at how they work.
Creating a Function
In much the same way as variables are declared with the var keyword, functions are declared using the function keyword followed by the name you wish to give to the function. However, when you declare a function you are required to include two additional items: a pair of parentheses and a pair of curly braces, as shown in the example below:
function functionName(){}
NOTE
JavaScript functions are named according to the same rules that are used for naming variables. They can contain alphanumeric characters, the underscore character, and the dollar sign as long as you do not use a JavaScript keyword. The first character cannot be a number. Remember also to give your functions meaningful names.
We will discuss the function of the parentheses shortly, so let's concentrate on the curly braces for now. The curly braces (or "curly brackets" as they are sometimes called) act as code containers. All the code that is to be contained by the function (termed the function body) has to be placed between them. Essentially, the curly braces tell the JavaScript interpreter where the function body starts and where it ends. Here is an example of a function with some code:
function myFirstFunction(){ alert("I'm in a function!") }
As functions usually contain more than a single line of code, it is usual to break the curly braces over more than one line, as shown below:
function myFunction(){ . code . }
or sometimes the code is written like this:
function myFunction() { . code . }
CAUTION
Do not put a semi-colon (;) after the parentheses or after the curly braces. This will cause an error.
The JavaScript interpreter will treat both methods of code layout the same way. The JavaScript interpreter knows that functions aren't finished until it has reached a closing curly brace so it ignores the extraneous white space. The aim of spreading code across several lines and indenting statements is to make the start and end of your function stand out so that when you scan large sections of code you can immediately pick out function names and where their code begins and ends. Which method you use is up to you.
Let's create a page that contains a function that will greet a visitor by name. Use the template in Listing 1.6 and add to it the function in the following code. After you have created the page, save it, and load it into your browser. See Listing 3.1.
Listing 3.1 Creating a Function (storedGreeting.htm)
<html> <head> <title>Function Demo</title> <script language="javascript" type="text/javascript"> <!-- function greetVisitor() { var myName = prompt("Please enter your name.", ""); alert("Welcome " + myName + "!") } //--> </script> </head> <body> <h1>Function Demo</h1> </body> </html>
As you will see, the page loads without an error but the JavaScript contained within the function body doesn't run. Hopefully this was what you expected. Remember, functions store codewe have yet to learn how to evaluate the code.
Using Functions
To evaluate the function's code (or as we are going to refer to it from now on, "to call the function"), we need to write out something termed a function call. To do this, simply write the function's name followed by opening and closing parentheses. The parentheses tell the JavaScript interpreter to call the function immediately and to run its code before it does anything else. Therefore to call the function in your page, simply write the following line under the function declaration:
greetVisitor();
If you load your page with these changes, the function should be called, and you then will be prompted for your name and greeted.
CAUTION
As with the var keyword for variables, the function keyword is only used one timethe first time you declare a function. It is not used when you call it.
Function calls can be placed anywhere in a script block (and can be placed in event handlers, as you will learn later in the book). For the moment, though, to call our functions, we are going to use the ability of anchor tags to execute JavaScript using their href attribute. To do this, simply write "javascript" followed by a colon and a JavaScript statement between the href's quote marks. To see this at work, add the following line to the body of an HTML document and click on the hyperlink it produces.
<a href="javascript:alert('You clicked on the link!')">Click Here!</a>
This can be used to call functions simply by replacing the alert function with a function call to one of your own functions.
Go back to your page for greeting a visitor and add a hyperlink that calls the function as shown in Listing 3.2. Resave the page, and then open it with your browser.
Listing 3.2 Creating a Function (storedGreeting2.htm)
<html> <head> <title>Calling a Function</title> <script language="javascript" type="text/javascript"> <!-- function greetVisitor() { var myName = prompt("Please enter your name.", ""); alert("Welcome " + myName + "!") } //--> </script> </head> <body> <h1>Please click below and enter your name when prompted.</h1> <p><a href="javascript:greetVisitor()">Click for a greeting</a></p> </body> </html>
As you will see, the page loads without the alert box displaying. Now try clicking on the hyperlink. This will call the function, and the prompt for your name should appear as shown in Figure 3.1.
Figure 3.1 A prompt box requests your name.
Fill in your name and an alert box will appear to greet you. You will see later in the chapter how to handle situations when someone may not fill in the prompt or they may click Cancel.
Hopefully you now see how simple functions are created and used, and you understand why they are so essential. Without functions JavaScript couldn't do anything after the page had loaded. With them, you can create countless interactive or useful enhancements.
Sending Data to Functions
Frequently, when creating a function you will want to give it some data on which to work. This allows you to perform the same process repeatedly on different sets of data. The process of sending data to a function is termed passing data to a function, which means that the data to be passed is written into the parentheses of the function call. For example, to send the numeric value 10 to a function called squareNum() you would write:
squareNum(10);
Sometimes you will need to extend this process so that more than one piece of data can be passed to a function. This can be accomplished by placing each piece of data to be passed to the function within the parentheses, and separating each of them with a comma. For example, if you wanted to send two different strings followed by the number 3 and the Boolean value true to a function called processThis(), you would write:
processThis("1st string", "2nd string", 3, true);
As you will see later, the order in which these pieces of data are written between the parentheses is important to the correct functioning of a function.
All these pieces of data that are sent to a function for use in the code that the function contains are known as arguments (or parameters) of the function. Now that you can pass arguments to a function, let's see how you can use them in the function body.
Using Arguments
There are two ways of grabbing the arguments that are passed to functions. For the moment, we will deal with the simpler and more popular of the two.
The usual method of accessing arguments is to write names into the parentheses of the function declaration that correspond to the arguments written into the function call. For example, say you have a function called numOddOrEven() that calculates whether the single numeric argument that is passed to it is odd or even. To call the function and send it the number 9, you would write the following:
numOddOrEven(9);
To use this number in the function, a name must have been written in the parentheses when the function was defined. For example, if the name theNum was used, it might look like this:
function numOddOrEven(theNum) { numType = (theNum % 2)? "odd": "even"; alert("The number " +theNum+ " is an " +numType+ " number."); }
For the moment, you don't need to worry about how the function works. The important thing to note is the way that theNum is used repeatedly throughout the function block. Effectively, the name (or names) contained within the parentheses acts exactly like a variable. Wherever it is used in the function body, the theNum is replaced by the data that was sent to the function as an argument (in this case the number 9).
The method of separating arguments with commas is also used to separate the argument names in the function declaration's parentheses. To use two arguments in the function, you would declare it as shown below:
function numsOddOrEven(num1, num2) { numType1 = (num1 % 2)? "odd": "even"; numType2 = (num2 % 2)? "odd": "even"; alert("The number " +num1+ " is an " +numType1+ " number."); alert("The number " +num2+ " is an " +numType2+ " number."); }
To call this function and send it the numbers 5 and 10, you would write the function call as shown below:
numsOddOrEven(5, 10);
This would result in the two alert boxes shown in Figures 3.2 and 3.3.
Figure 3.2 Alert showing the type of the first argument passed to the numsOddOrEven() function.
Figure 3.3 Alert showing the type of the second argument passed to the numsOddOrEven() function.
Note the order in which the alert boxes appear. The argument name num1, which comes first in the parentheses of the function declaration, takes the value 5, which was given first in the function call. Likewise num2, which came second in the function declaration, takes the value 10, which came second in the function call.
CAUTION
Always be careful to provide data in the correct order. If you confuse the order in which you provide the arguments to a function, you will likely get an unexpected result or an error.
Another thing to note is that if you have declared your function with argument names in the parentheses, you do not necessarily have to send them data with the function call. If arguments aren't sent, then the argument names will simply have the value undefined. For example, try calling the following function both with and without an argument:
function checkForArg(myArg) { var msg = "The function argument was "; // Start message // Add ending based on whether an argument has been sent msg += myArg? myArg: "not sent!"; alert(msg); } checkForArg();
The conditional operator concatenates the argument passed to the function to the variable msg, if an argument has been passed to the function. If no argument has been passed to the function, then the string "not sent!" is concatenated to the msg variable.
This feature can be useful if for some reason you want to code your function so it does not rely on being sent arguments. But that would be an unusual situation.
CAUTION
Be careful about passing the correct number of arguments to a function, since most of your functions will only operate correctly if the correct number of parameters is passed to the function. With no parameters or an incorrect number passed to the function an unexpected result or an error may occur.
Returning Data from a Function
Very often you will want functions to give back data after they have processed the data that was sent to them. To do this we use the return statement. Take a look at this example before we walk through it:
function getModulus(theNum) { var theModulus = (theNum>=0)? theNum: -theNum; return theModulus; } var myNum = -12; myNum = getModulus(myNum); alert(myNum);
Notice that the function call is on the right-hand side of an assignment to a variable called myNum, and that the function is sent the original value of myNum as an argument. The first line of the function processes the number to find its modulus (the number 12) prior to storing it in the variable theModulus.
NOTE
The modulus of a number is the same as the number if the number is greater than zero. If the number is less than zero, then its modulus is the negation of the numberthat is, the modulus of -5 is 5. The modulus is sometimes referred to as the absolute value of the number.
It is the next line that is really of interest here. It uses the return keyword to return the value of the variable theModulus to the point in the code where the function call is situated. In this case, the function call was to the right of the = assignment operator. Therefore the value 12 is assigned to the variable myNum replacing its original value of -12. This is shown when the alert box displays myNum's value (see Figure 3.4).
Figure 3.4 An alert showing the value of myNum, which is the value returned by the getModulus () function.
The return statement does indeed return data from the function to wherever the function call was located. However, there is another characteristic of the return statement that the above example doesn't clearly demonstrate. When the return statement is evaluated it stops any further evaluation of the function body. Enter the following into the template from Listing 1.6 and try it out:
function returnTest() { alert("This will alert."); return; alert("This won't alert."); alert("Neither will this."); alert("Or this."); } returnTest();
In this example, the first alert would be the only one to be evaluated, and therefore displayed, because the return statement stops the function from continuing to the end of the function body.
A return statement can have two effects. When a return keyword is encountered it always stops a function from further evaluation. If provided with some data, the return statement will return the data to the place in the code where the function call is situated. If the return statement is not provided with data, it will simply return undefinedjust as a function without a return statement would.
Variable Scope
As promised in Chapter 2, let's now look more closely at the differences that including or omitting the var keyword during declaration of a variable would make on the variables in your JavaScript code. The reason for putting this examination off until now is because it is in functions that your choice of including or omitting the var keyword has the most significant effect.
Before we go on to find out more about the scope of a function, let's first take a look at the meaning of the word scope.
The word scope refers to the limits inside which something is applicable. For example, in the United States there are two types of law: federal law and state law. State law is only applicable in individual states and therefore due to its geographical limitation, it might be referred to as having "local" scope. Federal law, on the other hand, isn't limited by state boundaries. It governs the whole country, so it might be said that, as far as the United States is concerned, it has "global" scope.
The idea of local and global scopes also exists for JavaScript variables. When a variable is termed a global variable it means that it can be accessed and used by any part of any of the scripts in the same HTML document. In addition, you also can use global variables in scripts that are in a different frame or browser window (although we haven't covered that yet). All variables declared in the script block, but outside of functions, have global scope.
Variables defined inside a function are different. Their scope depends on whether you do or do not declare them with the var keyword. If a variable is declared within a function without the var keyword, then its scope is global. If a variable is declared within a function using the var keyword, then its scope is local.
The problem with creating global variables from inside a function may not be immediately apparent. What tends to happen is that functions use temporary variables that are of use only while the function is evaluating. Outside the function they aren't needed. It is easy in a long piece of code to forget some of the global variable names and give one or more of the variables inside a function the same name as a global variable which already exists. If you have not included the var keyword when a variable is declared within a function, then the variable is global in scope and the data in the global variable with the same name outside the function is overwritten. This can play havoc with your scripts, and it can be very hard to track down the problem, as error messages that may be generated won't tell you from where the problem stems. The JavaScript interpreter is doing what you told it to do, but it is doing something that you may well not have expected it to do.
Creating local variables enables you to eliminate the possibility that this type of problem will ever arise. If you happen to unintentionally use the same name for a variable in a function and a variable in the main script block, then as long as you used the var keyword an entirely different local variable is created inside the function.
NOTE
Local variables are not only limited to the function in which they were defined, but they also only exist for the time it takes for the function to execute. As soon as the function body has been evaluated, local variables cease to exist and the data they contained is discarded.
Here is an example that will show you the effect of declaring a variable within a function. Run it both with and without the var keyword in front of the variable testVariable in the function.
First, if you run it with the var keyword within the function, the value of the global variable will not be overwritten.
var testVariable = "Global variable was NOT overwritten!"; function someFunction() { var testVariable = "Global variable WAS overwritten!"; } someFunction(); alert(testVariable);
However, if you run the following code with the var keyword omitted in the declaration of the variable within the function, then the global variable will be overwritten.
var testVariable = "Global variable was NOT overwritten!"; function someFunction() { testVariable = "Global variable WAS overwritten!"; } someFunction(); alert(testVariable);
In summary, unless you specifically want the function to change the value of a global variable you should always declare variables inside of functions with the var keyword. It may seem tedious, but if you get into this good habit of using the var keyword all the time, you will ensure that you don't accidentally overwrite an important global variable in a long complex script.
CAUTION
If you are using publicly available JavaScript code written by someone else with your own code, you need to be particularly careful. The way the other script author uses variables could be similar to your own, and one of your local variables could overwrite one of his global variables, causing problems that could be very difficult to track down.