Chapter 5

Harnessing the Power of Functions

IN THIS CHAPTER

check Getting to know JavaScript functions

check Creating and using custom functions

check Passing and returning function values

check Understanding recursive functions

check Introducing JavaScript’s built-in functions

To iterate is human, to recurse divine.

— L. PETER DEUTSCH

As I demonstrate throughout this book, JavaScript comes with a huge number of built-in features that perform specific tasks. For example, something called the Math object has a built-in method for calculating the square root of a number. Similarly, a feature called the String object has a ready-made method for converting a string value to all lowercase letters.

There are, in fact, hundreds of these ready-to-roll features that perform tasks that range from the indispensable to the obscure. But JavaScript can't possibly do everything that you’d like or need it to do. What happens if your web development project requires a particular task or calculation that isn’t part of the JavaScript language? Are you stuck? Not even close! The solution is to roll up your sleeves and then roll your own code that accomplishes the task or runs the calculation.

This chapter shows you how to create such do-it-yourself code. In the pages that follow, you explore the powerful and infinitely useful realm of custom functions, where you craft reusable code that performs tasks that out-of-the-box JavaScript can’t do.

What Is a Function?

A function is a group of related JavaScript statements that are separate from the rest of the script and that perform a designated task. (Technically, a function can perform any number of chores, but as a general rule it’s best to have each function focus on a specific task.) When your script needs to perform that task, you tell it to run the function.

Functions are also useful for those times when you need to control exactly when a particular task occurs (if ever). If you just enter some statements between your web page’s <script> and </script> tags, the browser executes those statements automatically when the page loads. However, the statements within a function aren't executed by the browser automatically. Instead, the function doesn’t execute until either your code asks the function to run, or some event occurs — such as the user clicking a button — and you’ve set up your page to run the function in response to that event.

The Structure of a Function

The basic structure of a function looks like this:

function functionName([arguments]) {

JavaScript statements

}

Here’s a summary of the various parts of a function:

  • function: Identifies the block of code that follows it as a function.
  • functionName: A unique name for the function. The naming rules and guidelines that I outline for variables in Book 3, Chapter 2 also apply to function names.
  • arguments: One or more optional values that are passed to the function and that act as variables within the function. Arguments (or parameters, as they're sometimes called) are typically one or more values that the function uses as the raw materials for its tasks or calculations. You always enter arguments between parentheses after the function name, and you separate multiple arguments with commas. If you don’t use arguments, you must still include the parentheses after the function name.
  • JavaScript statements: This is the code that performs the function’s tasks or calculations.

tip Notice how the JavaScript statements line in the example is indented slightly from the left margin. This is a standard and highly recommended programming practice because it makes your code easier to read. This example is indented four spaces, which is enough to do the job, but isn't excessive.

Note, too, the use of braces ({ and }). These are used to enclose the function’s statements within a block, which tells you (and the browser) where the function’s code begins and ends. There are only two rules for where these braces appear:

  • The opening brace must appear after the function’s parentheses and before the first function statement.
  • The closing brace must appear after the last function statement.

There is no set-in-stone rule that specifies exactly where the braces appear. The positions used in the previous function syntax are the traditional ones, but you’re free to try other positions, if you want. For example:

function functionName([arguments])

{

JavaScript statements

}

Where Do You Put a Function?

For most applications, it doesn’t matter where you put your functions, as long as they reside within a <script> block. However, one of the most common uses of functions is to handle events when they’re triggered. It’s possible that a particular event might fire when the page is loading, and if that happens before the browser has parsed the corresponding function, you could get strange results or an error. To prevent that, it’s good practice to place the script containing all your functions within the page’s header section (or within an external JavaScript file).

Note, as well, that you can add as many functions as you want within a single <script> block, but there are two things to watch out for:

  • Each function must have a unique name. In fact, all the functions that exist in or are referenced by a page must have unique names.
  • You can't embed one function inside another function.

Calling a Function

After your function is defined, you’ll eventually need to tell the browser to execute it, or call it. There are three main ways to do this:

  • When the browser parses the <script> tag.
  • After the page is loaded.
  • In response to an event, such as the user clicking a button.

The next three sections cover each of these scenarios.

Calling a function when the <script> tag is parsed

The simplest way to call a function is to include in your script a statement consisting of only the function name, followed by parentheses (assuming for the moment that your function uses no arguments.) The following code provides an example. (I’ve listed the entire page so you can see where the function and the statement that calls it appear in the page code.)

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Calling a function when the &lt;script&gt; tag is parsed</title>

<script>

function displayGreeting() {

var currentHour = new Date().getHours();

if (currentHour < 12) {

console.log("Good morning!");

} else {

console.log("Good day!");

}

}

displayGreeting();

</script>

</head>

<body>

</body>

</html>

The <script> tag includes a function named displayGreeting, which determines the current hour of the day, and then writes a greeting to the console based on whether it's currently morning. The function is called by the displayGreeting() statement that appears just after the function.

Calling a function after the page is loaded

If your function references a page element, then calling the function from within the page’s head section won’t work because when the browser parses the script, the rest of the page hasn’t loaded yet, so your element reference will fail.

To work around this problem, place another <script> tag at the end of the body section, just before the closing </body> tag, as shown here:

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Calling a function after the page is loaded</title>

<script>

function makeBackgroundRed() {

document.body.style.backgroundColor = "red";

console.log("The background is now red.");

}

</script>

</head>

<body>

<!-- Other body elements go here -->

<script>

makeBackgroundRed();

</script>

</body>

</html>

The makeBackgroundRed() function does two things: It uses document.body.style.backgroundColor to change the background color of the body element to red, and it uses console.log() to write a message to that effect on the console.

In the function, document.body is a reference to the body element, which doesn't “exist” until the page is fully loaded. That means if you try to call the function with the initial script, you’ll get an error. To execute the function properly, a second <script> tag appears at the bottom of the body element and that script calls the function with the following statement:

makeBackgroundRed();

Since by the time the browser executes that statement the body element exists, the function runs without an error.

Calling a function in response to an event

One of the most common ways that JavaScript functions are called is in response to some event. This is such an important topic that I devote an entire chapter to it later in the book (see Book 4, Chapter 2). For now, take a look at a relatively straightforward application: executing the function when the user clicks a button. The following code shows one way to do it.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Calling a function in response to an event</title>;

<script>

function makeBackgroundRed() {

document.body.style.backgroundColor= "red";

}

function makeBackgroundWhite() {

document.body.style.backgroundColor= "white";

}

</script>

</head>

<body>

<button onclick="makeBackgroundRed()">

Make Background Red

</button>

<button onclick="makeBackgroundWhite()">

Make Background White

</button>

</body>

</html>

What I've done here is place two functions in the script: makeBackgroundRed() changes the page background to red, as before, and makeBackgroundWhite() changes the background color back to white.

The buttons are standard HTML button elements, each of which includes the onclick attribute. This attribute defines a handler — that is the function to execute — for the event that occurs when the user clicks the button. For example, consider the first button:

<button onclick="makeBackgroundRed()">

The onclick attribute here says, in effect, “When somebody clicks this button, call the function named makeBackgroundRed().”

Passing Values to Functions

One of the main reasons to use functions is to gain control over when some chunk of JavaScript code gets executed. The previous section, for example, discusses how easy it is to use functions to set things up so that code doesn't run until the user clicks a button.

However, there’s another major reason to use functions: to avoid repeating code unnecessarily. To see what I mean, consider the two functions from the previous section:

function makeBackgroundRed() {

document.body.style.backgroundColor= "red";

}

function makeBackgroundWhite() {

document.body.style.backgroundColor= "white";

}

These functions perform the same task — changing the background color — and the only difference between them is one changes the color to red and the other changes it to white. Whenever you end up with two or more functions that do essentially the same thing, then you know that your code is inefficient.

So how do you make the code more efficient? That’s where the arguments that I mention earlier come into play. An argument is a value that is “sent” — or passed, in programming terms — to the function. The argument acts just like a variable, and it automatically stores whatever value is sent.

Passing a single value to a function

As an example, you can take the previous two functions, reduce them to a single function, and set up the color value as an argument. Here’s a new function that does just that:

function changeBackgroundColor(newColor) {

document.body.style.backgroundColor = newColor;

}

The argument is named newColor and it’s added between the parentheses that occur after the function name. JavaScript declares newColor as a variable automatically, so there's no need for a separate var statement. The function then uses the newColor value to change the background color. So how do you pass a value to the function? The following code presents a sample file that does this.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Passing a single value to a function</title>;

<script>

function changeBackgroundColor(newColor) {

document.body.style.backgroundColor = newColor;

}

</script>

</head>

<body>

<button onclick="changeBackgroundColor('red')">

Make Background Red

</button>

<button onclick="changeBackgroundColor('white')">

Make Background White

</button>

</body>

</html>

The key here is the onclick attribute that appears in both <button> tags. For example:

onclick="changeBackgroundColor('red')"

The string 'red' is inserted into the parentheses after the function name, so that value is passed to the function itself. The other button passes the value 'white', and the function result changes accordingly.

warning In the two onclick attributes in the example code, notice that the values passed to the function are enclosed in single quotation marks ('). This is necessary because the onclick value as a whole is enclosed in double quotation marks (").

Passing multiple values to a function

For more complex functions, you might need to use multiple arguments so that you can pass different kinds of values. If you use multiple arguments, separate each one with a comma, like this:

function changeColors(newBackColor, newForeColor) {

document.body.style.backgroundColor = newBackColor;

document.body.style.color = newForeColor;

}

In this function, the document.body.style.color statement changes the foreground color (that is, the color of the page text). The following code shows a revised page where the buttons pass two values to the function.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="utf-8">

<title>Passing multiple values to a function</title>;

<script>

function changeColors(newBackColor, newForeColor) {

document.body.style.backgroundColor = newBackColor;

document.body.style.color = newForeColor;

}

</script>

</head>

<body>

<h1>Passing Multiple Values to a Function</h1>

<button onclick="changeColors('red', 'white')">

Red Background, White Text

</button>

<button onclick="changeColors('white', 'red')">

White Background, Red Text

</button>

</body>

</html>

warning If you define a function to have multiple arguments, then you must always pass values for each of those arguments to the function. If you don't, then the “value” undefined is passed, instead, which can cause problems.

technicalstuff If you use a variable to pass data to a function, only the current value of that variable is sent, not the variable itself. Therefore, if you change the value of the argument within the function, the value of the original variable isn’t changed. Here’s an example:

var passThis = 10;

function sendMe(acceptThis) {

acceptThis = 5;

}

sendMe(passThis);

console.log(passThis);

The variable passThis starts off with a value of 10. The function sendMe() is then defined to accept an attribute named acceptThis, and to then change the value of that attribute to 5. sendMe() is then called and the value of the passThis variable is passed to it. Then a console.log() statement displays the value of passThis. If you run this code, the displayed value will be 10, the original value of passThis. In other words, changing the value of acceptThis within the function had no effect on the value of the passThis variable.

Returning a Value from a Function

So far I've outlined two major advantages of using functions:

  • You can use them to control when code is executed.
  • You can use them to consolidate repetitive code into a single routine.

The third major benefit that functions bring to the JavaScript table is that you can use them to perform calculations and then return the result. As an example, I construct a function that calculates the tip on a restaurant bill:

var preTipTotal = 100.00;

var tipPercentage = 0.15;

function calculateTip(preTip, tipPercent) {

var tipResult = preTip * tipPercent;

return (tipResult);

}

var tipCost = calculateTip(preTipTotal, tipPercentage);

var totalBill = preTipTotal + tipCost;

console.log("Your total bill is $" + totalBill);

The function named calculateTip() takes two arguments: preTip is the total of the bill before the tip, and tipPercent is the percentage used to calculate the tip. The function then declares a variable named tipResult and uses it to store the calculation — preTip multiplied by tipPercent. The key for this example is the second line of the function:

return (tipResult);

The return statement is JavaScript's way of sending a value back to the statement that called the function. That statement comes after the function:

tipCost = calculateTip(preTipTotal, tipPercentage);

This statement first passes the value of preTipTotal (initialized as 100.00 earlier in the script) and tipPercentage (initialized as 0.15 earlier) to the calculateTip() function. When that function returns its result, the entire expression calculateTip(preTipTotal, tipPercentage) is replaced by that result, meaning that it gets stored in the tipCost variable. Then preTipTotal and tipCost are added together, the result is stored in totalBill, and a console.log statement displays the final calculation.

Understanding Local versus Global Variables

In the example I give in the previous section, notice that there are four variables declared outside the function (preTipTotal, tipPercentage, tipCost, and totalBill) and one variable declared inside the function (tipPercent). That might not seem like an important distinction, but there's a big difference between variables declared outside of functions and those declared inside of functions. This section explains this crucial difference.

In programming, the scope of a variable defines where in the script a variable can be used and where it can’t be used. To put it another way, a variable’s scope determines which statements and functions can access and work with the variable. There are two main reasons you need to be concerned with scope:

  • You might want to use the same variable name in multiple functions. If these variables are otherwise unrelated, you’ll want to make sure that there is no confusion about which variable you’re working with. In other words, you’ll want to restrict the scope of each variable to the function in which it is declared.
  • You might need to use the same variable in multiple functions. For example, your function might use a variable to store the results of a calculation, and other functions might also need to use that result. In this case, you’ll want to set up the scope of the variable so that it’s accessible to multiple functions.

JavaScript lets you establish two types of scope for your variables:

  • Local (or function-level) scope
  • Global (or page-level) scope

The next two sections describe each type in detail.

Working with local scope

When a variable has local scope, it means the variable was declared inside a function and the only statements that can access the variable are the ones in that same function. (That’s why local scope also is referred to as function-level scope.) Statements outside the function and statements in other functions can’t access the local variable.

To demonstrate this, consider the following code:

function A() {

var myMessage;

myMessage = "I'm in the scope!";

console.log("Function A: " + myMessage);

}

function B() {

console.log("Function B: " + myMessage);

}

A();

B();

There are two functions here, named A() and B(). Function A() declares a variable named myMessage, sets its value to a text string, and uses JavaScript's console.log() method to display the string in the console.

Function B() also uses console.log() to attempt to display the myMessage variable. However, as you can see in Figure 5-1, JavaScript generates an error that says myMessage is not defined. Why? Because the scope of the myMessage variable extends only to function A(); function B() can't “see” the myMessage variable, so it has nothing to display. In fact, after function A() finishes executing, JavaScript removes the myMessage variable from memory entirely, so that's why the myMessage variable referred to in function B() is undefined.

image

FIGURE 5-1: Attempting to display the myMessage variable in function B() results in an error.

The same result occurs if you attempt to use the myMessage variable outside of any function, as in the following code:

function A() {

var myMessage;

myMessage = "I'm in the scope!";

console.log("Function A: " + myMessage);

}

A();

// The following statement generates an error:

console.log(myMessage);

Working with global scope

What if you want to use the same variable in multiple functions or even in multiple script blocks within the same page? In that case, you need to use global scope, which makes a variable accessible to any statement or function on a page. (That's why global scope is also called page-level scope.) To set up a variable with global scope, declare it outside any function. The following code gives this a whirl:

var myMessage = "I've got global scope!";

function C() {

console.log("Function C: " + myMessage);

}

C();

console.log("Outside the function: " + myMessage);

The script begins by declaring the myMessage variable and setting it equal to a string literal. Then a function named C() is created and it displays a console message that attempts to display the value of myMessage. After the function is called, another console.log() statement attempts to display the myMessage value outside of the function. Figure 5-2 shows the results. As you can see, both console.log() statements display the value of myMessage without a problem.

image

FIGURE 5-2: When you declare a global variable, you can access its value both inside and outside of a function.

Using Recursive Functions

One of the stranger things you can do with a function is have it execute itself. That is, you place a statement within the function that calls the function. This is called recursion, and such a function is called a recursive function.

Before trying out a practical example, I begin with a simple script that demonstrates the basic procedure:

var counter = 0;

addOne();

function addOne() {

counter++;

if (confirm("counter is now " + counter + ". Add another one?")) {

addOne();

}

}

console.log("Counter ended up at " + counter);

The script begins by declaring a variable named counter and initializing it to 0. Then a function named addOne() is called. This function increments the value of counter. It then displays the current value of counter and asks if you want to add another. If you click OK, the addOne() function is called again, but this time it's called from within addOne() itself! This just means that the whole thing repeats itself until you eventually click Cancel in the dialog box. After the function is exited for good, a console.log() statement shows the final counter total.

What possible use is recursion in the real world? That's a good question. Consider a common business problem: calculating a profit-sharing plan contribution as a percentage of a company’s net profits. This isn’t a simple multiplication problem, because the net profit is determined, in part, by the profit-sharing figure. For example, suppose that a company has sales of $1,000,000 and expenses of $900,000, which leaves a gross profit of $100,000. The company also sets aside 10 percent of net profits for profit sharing. The net profit is calculated with the following formula:

Net Profit = Gross Profit - Profit Sharing Contribution;

That looks straightforward enough, but it’s really not because the Profit Sharing Contribution value is derived with the following formula:

Profit Sharing Contribution = Net Profit * 10%;

In other words, the Net Profit value appears on both sides of the equation, which complicates things considerably.

One way to solve the Net Profit formula is to guess at an answer and see how close you come. For example, because profit sharing should be 10 percent of net profits, a good first guess might be 10 percent of gross profits, or $10,000. If you plug this number into the Net Profit formula, you get a value of $90,000. This isn't right, however, because you’d end up with a profit sharing value — 10 percent of $90,000 — of $9,000. Therefore, the original profit-sharing guess is off by $1,000.

So you can try again. This time, use $9,000 as the profit-sharing number. Plugging this new value into the Net Profit formula returns a value of $91,000. This number translates into a profit-sharing contribution of $9,100. This time you’re off by only $100, so you’re getting closer.

If you continue this process, your profit-sharing guesses will get closer to the calculated value (this process is called convergence). When the guesses are close enough (for example, within a dollar), you can stop and pat yourself on the back for finding the solution.

This process of calculating a formula and then continually recalculating it using different values is what recursion is all about, so let’s see how you’d go about writing a script to do this for you. Take a look at the following code.

var grossProfit = 100000;

var netProfit;

var profitSharingPercent = 0.1;

// Here's the initial guess

var profitSharing = grossProfit * profitSharingPercent;

calculateProfitSharing (profitSharing);

function calculateProfitSharing(guess) {

// First, calculate the new net profit

netProfit = grossProfit - guess;

// Now use that to guess the profit sharing value again

profitSharing = Math.ceil(netProfit * profitSharingPercent);

// Do we have a solution?

if ((netProfit + profitSharing) != grossProfit) {

// If not, plug it in again

calculateProfitSharing (profitSharing);

}

}

console.log("Gross Profit: " + grossProfit + " Net Profit: " + netProfit + " Profit Sharing: " + profitSharing);

The grossProfit variable is initialized at 100000, the netProfit variable is declared, the profitSharingPercent variable is set to 0.1 (10 percent), and the profitSharing variable is set to the initial guess of 10 percent of gross profits. Then the calculateProfitSharing() function is called, and the profitSharing guess is passed as the initial value of the guess argument.

The function first calculates the netProfit and then uses that value to calculate the new profitSharing number. Remember your goal here is to end up with the sum of netProfit and profitSharing being equal to grossProfit. The if statement tests that, and if the sum is not equal to grossProfit, the calculateProfitSharing() function is called again (here's the recursion), and this time the new profitSharing value is passed. When the correct values are finally found, the function exits and a console message displays the results, as shown in Figure 5-3.

image

FIGURE 5-3: Using recursion to calculate a profit sharing value.

remember Note that all the variables in previous example are declared as globals. That’s because if you declared them within the calculateProfitSharing() function, they would get wiped out and reset with each call, which is not what you want when doing recursion.

..................Content has been hidden....................

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