Chapter 5
IN THIS CHAPTER
Getting to know JavaScript functions
Creating and using custom functions
Passing and returning function values
Understanding recursive functions
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.
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 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.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:
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
}
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:
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:
<script>
tag.The next three sections cover each of these scenarios.
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 <script> 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.
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.
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 makeBackground
White()
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()
.”
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.
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.
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>
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.
So far I've outlined two major advantages of using functions:
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.
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:
JavaScript lets you establish two types of scope for your variables:
The next two sections describe each type in detail.
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.
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);
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.
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.
3.136.97.64