A function is a way to bundle code so that it can be reused. Functions allow us to run the same piece of code from multiple places in a program without having to copy and paste the code repeatedly. Also, by hiding long bits of code in a function and giving it an easy-to-understand name, you’ll be better able to plan out your code because you can focus on organizing your functions rather than all of the little code details that make them up. Splitting up your code into smaller, more manageable pieces allows you to see the bigger picture and think about how your programs are structured at a higher level.
You’ll find functions really useful when you need to repeatedly perform a calculation or action throughout a program. Earlier in the book, you used various functions such as Math.random
, Math.floor
, alert
, prompt
, and confirm
. In this chapter, you’ll learn how to create your own functions.
Figure 8-1 shows how a function is built. The code between the curly brackets is called the function body, just as the code between the curly brackets in a loop is called the loop body.
Let’s create a simple function that prints Hello world!
. Enter the following code in the browser console. Use SHIFT-ENTER to start each new line without executing the code.
var ourFirstFunction = function () { console.log("Hello world!"); };
This code creates a new function and saves it in the variable ourFirstFunction
.
To run the code inside a function (the function body), we need to call the function. To call a function, you enter its name followed by a pair of opening and closing parentheses, as shown here.
ourFirstFunction();
Hello world!
Calling ourFirstFunction
executes the body of the function, which is console.log("Hello world!");
, and the text we asked to be printed is displayed on the next line: Hello world!
.
But if you call this function in your browser, you’ll notice that there’s a third line, with a little left-facing arrow, as shown in Figure 8-2. This is the return value of the function.
A return value is the value that a function outputs, which can then be used elsewhere in your code. In this case, the return value is undefined
because we didn’t tell the function to return any particular value in the body of the function. All we did was ask it to print a message to the console, which is not the same as returning a value. A function always returns undefined
unless there is something in the function body that tells it to return a different value. (We’ll look at how to specify a return value in Returning Values from Functions.)
ourFirstFunction
just prints the same line of text every time you call it, but you’ll probably want your functions to be more flexible than that. Function arguments allow us to pass values into a function in order to change the function’s behavior when it’s called. Arguments always go between the function parentheses, both when you create the function and when you call it.
The following sayHelloTo
function uses an argument (name
) to say hello to someone you specify.
var sayHelloTo = function (name) { console.log("Hello " + name + "!"); };
We create the function in the first line and assign it to the variable sayHelloTo
. When the function is called, it logs the string "Hello " + name + "!",
replacing name
with whatever value you pass to the function as an argument.
Figure 8-3 shows the syntax for a function with one argument.
To call a function that takes an argument, place the value you’d like to use for the argument between the parentheses following the function name. For example, to say hello to Nick, you would write:
sayHelloTo("Nick");
Hello Nick!
Or, to say hello to Lyra, write:
sayHelloTo("Lyra");
Hello Lyra!
Each time we call the function, the argument we pass in for name
is included in the string printed by the function. So when we pass in "Nick"
, the console prints "Hello Nick!"
, and when we pass in "Lyra"
, it prints "Hello Lyra!"
.
One reason to pass an argument into a function might be to tell it how many times to do something. For example, the function drawCats
prints cat faces (like this: =^.^=
) to the console. We tell the function how many cats to print using the argument howManyTimes
:
var drawCats = function (howManyTimes) { for (var i = 0; i < howManyTimes; i++) { console.log(i + " =^.^="); } };
The body of the function is a for
loop that loops as many times as the howManyTimes
argument tells it to (since the variable i
starts at 0 and repeats until it increments to howManyTimes
minus 1). Each time through the loop, the function logs the string i + " =^.^="
.
Here’s what happens when we call this function with the argument 5
for howManyTimes
:
drawCats(5);
0 =^.^=
1 =^.^=
2 =^.^=
3 =^.^=
4 =^.^=
Try it out with howManyTimes
equal to 100
to print 100 cat faces!
You can pass more than one value into a function using multiple arguments. To add another argument, enter the arguments between the parentheses after the function
keyword, separating them by commas. Figure 8-4 shows the syntax for a function with two arguments.
The following function, printMultipleTimes
, is like drawCats
except that it has a second argument called whatToDraw
.
var printMultipleTimes = function (howManyTimes, whatToDraw) { for (var i = 0; i < howManyTimes; i++) { console.log(i + " " + whatToDraw); } };
The printMultipleTimes
function prints the string you enter for whatToDraw
as many times as you specify with the argument howManyTimes
. The second argument tells the function what to print, and the first argument tells the function how many times to print it.
When calling a function with multiple arguments, insert the values you wish to use between the parentheses following the function name, separated by commas.
For example, to print out cat faces using this new printMultipleTimes
function, you’d call it like this:
printMultipleTimes(5, "=^.^=");
0 =^.^=
1 =^.^=
2 =^.^=
3 =^.^=
4 =^.^=
To have printMultipleTimes
print a happy face four times, you could do this:
printMultipleTimes(4, "^_^");
0 ^_^
1 ^_^
2 ^_^
3 ^_^
When we call printMultipleTimes
, we pass in the arguments 4
for howManyTimes
and "^_^"
for whatToDraw
. As a result, the for
loop loops four times (with i
incrementing from 0 to 3), printing i + " " + "^_^"
each time.
To draw the character (>_<)
two times, you could write:
printMultipleTimes(2, "(>_<)");
0 (>_<)
1 (>_<)
In this case, we pass in 2
for howManyTimes
and "(>_<)"
for whatToDraw
.
The functions we’ve looked at so far have all printed text to the console using console.log
. That’s an easy and useful way to make JavaScript display values, but when we log a value to the console, we aren’t able to use that value later in the program. What if you want your function to output that value so that you can keep using it in other parts of your code?
As mentioned earlier in this chapter, the output of a function is called the return value. When you call a function that returns a value, you can use that value in the rest of your code (you could save a return value in a variable, pass it to another function, or simply combine it with other code). For example, the following line of code adds 5 to the return value of the call to Math.floor(1.2345)
:
5 + Math.floor(1.2345); 6
Math.floor
is a function that returns the number you pass to it, rounded down to the nearest whole number. When you see a function call like Math.floor(1.2345)
, imagine replacing it with the return value of that function call, which is the number 1
.
Let’s create a function that returns a value. The function double
takes the argument number
and returns the result of number * 2
. In other words, the value returned by this function is twice the number supplied as its argument.
var double = function (number) { ➊ return number * 2; };
To return a value from a function, use the keyword return
, followed by the value you want to return. At ➊, we use the return
keyword to return the value number * 2
from the double
function.
Now we can call our double
function to double numbers:
double(3); 6
Here, the return value (6
) is shown on the second line. Even though functions can take multiple arguments, they can return only one value. If you don’t tell the function to return anything, it will return undefined
.
When you call a function from within a larger piece of code, the function’s return value is used wherever that function call was placed. For example, let’s use our double
function to determine the result of doubling two numbers and then adding the results:
double(5) + double(6); 22
In this example, we call the double
function twice and add the two return values together. You can think of the call double(5)
as the value 10
and the call double(6)
as the value 12
.
You can also pass a function call into another function as an argument, and the function call will be substituted with its return value. In this next example we call double
, passing the result of calling double
with 3
as an argument. We replace double(3)
with 6
so that double(double(3))
simplifies to double(6)
, which then simplifies to 12
.
double(double(3)); 12
Here’s how JavaScript calculates this:
The body of the double
function returns number * 2
, so at ➊ we replace double(3)
with 3 * 2
. At ➋ we replace 3 * 2
with 6
. Then at ➌, we do the same thing and replace double(6)
with 6 * 2
. Finally, at ➍, we can replace 6 * 2
with 12
.
In Chapter 3, we used the methods Math.random
and Math.floor
to pick random words from arrays and generate random insults. In this section, we’ll re-create our insult generator and simplify it by creating functions.
Here is the code we used in Chapter 3 to choose a random word from an array:
randomWords[Math.floor(Math.random() * randomWords.length)];
If we turn this code into a function, we can reuse it to pick a random word from an array without having to enter the same code each time. For example, here’s how we could define a pickRandomWord
function.
var pickRandomWord = function (words) { return words[Math.floor(Math.random() * words.length)]; };
All we’re doing here is wrapping the previous code in a function. Now, we can create this randomWords
array . . .
var randomWords = ["Planet", "Worm", "Flower", "Computer"];
and pick a random word from this array using the pickRandomWord
function, like this:
pickRandomWord(randomWords); "Flower"
We can use this same function on any array. For example, here’s how we would pick a random name from an array of names:
pickRandomWord(["Charlie", "Raj", "Nicole", "Kate", "Sandy"]); "Raj"
Now let’s try re-creating our random insult generator, using our function that picks random words. First, here’s a reminder of what the code from Chapter 3 looked like:
var randomBodyParts = ["Face", "Nose", "Hair"]; var randomAdjectives = ["Smelly", "Boring", "Stupid"]; var randomWords = ["Fly", "Marmot", "Stick", "Monkey", "Rat"]; // Pick a random body part from the randomBodyParts array: var randomBodyPart = randomBodyParts[Math.floor(Math.random() * 3)]; // Pick a random adjective from the randomAdjectives array: var randomAdjective = randomAdjectives[Math.floor(Math.random() * 3)]; // Pick a random word from the randomWords array: var randomWord = randomWords[Math.floor(Math.random() * 5)]; // Join all the random strings into a sentence: var randomString = "Your " + randomBodyPart + " is like a " + randomAdjective + " " + randomWord + "!!!"; randomString; "Your Nose is like a Stupid Marmot!!!"
Notice that we end up repeating words
[Math.floor(Math.random() *
length
)]
quite a few times in this code. Using our pickRandomWord
function, we could rewrite the program like this:
var randomBodyParts = ["Face", "Nose", "Hair"]; var randomAdjectives = ["Smelly", "Boring", "Stupid"]; var randomWords = ["Fly", "Marmot", "Stick", "Monkey", "Rat"]; // Join all the random strings into a sentence: var randomString = "Your " + pickRandomWord(randomBodyParts) + " is like a " + pickRandomWord(randomAdjectives) + " " + pickRandomWord(randomWords) + "!!!"; randomString; "Your Nose is like a Smelly Marmot!!!"
There are two changes here. First, we use the pickRandomWord
function when we need a random word from an array, instead of using words
[Math.floor(Math.random() *
length
)]
each time. Also, instead of saving each random word in a variable before adding it to the final string, we’re adding the return values from the function calls directly together to form the string. A call to a function can be treated as the value that the function returns. So really, all we’re doing here is adding together strings. As you can see, this version of the program is a lot easier to read, and it was easier to write too, since we reused some code by using a function.
We can take our random insult generator one step further by creating a larger function that produces random insults. Let’s take a look:
generateRandomInsult = function () { var randomBodyParts = ["Face", "Nose", "Hair"]; var randomAdjectives = ["Smelly", "Boring", "Stupid"]; var randomWords = ["Fly", "Marmot", "Stick", "Monkey", "Rat"]; // Join all the random strings into a sentence: var randomString = "Your " + pickRandomWord(randomBodyParts) + " is like a " + pickRandomWord(randomAdjectives) + " " + pickRandomWord(randomWords) + "!!!"; ➊ return randomString; }; generateRandomInsult(); "Your Face is like a Smelly Stick!!!" generateRandomInsult(); "Your Hair is like a Boring Stick!!!" generateRandomInsult(); "Your Face is like a Stupid Fly!!!"
Our new generateRandomInsult
function is just the code from before placed inside a function with no arguments. The only addition is at ➊, where we have the function return randomString
at the end. You can see a few sample runs of the preceding function, and it returns a new insult string each time.
Having the code in one function means we can keep calling that function to get a random insult, instead of having to copy and paste the same code every time we want a new insult.
As soon as the JavaScript interpreter reaches return
in a function, it leaves the function, even if more code remains in the function body.
One common way to use return
is to leave a function early if any of the arguments to the function are invalid; that is, if they’re not the kind of arguments the function needs in order to run properly. For example, the following function returns a string telling you the fifth character of your name. If the name passed to the function has fewer than five characters, the function uses return
to leave the function immediately. This means the return
statement at the end, which tells you the fifth letter of your name, is never executed.
var fifthLetter = function (name) { ➊ if (name.length < 5) { ➋ return; } return "The fifth letter of your name is " + name[4] + "."; };
At ➊ we check to see whether the length of the input name is less than five. If it is, we use return
at ➋ to exit the function early.
Let’s try calling this function.
fifthLetter("Nicholas"); "The fifth letter of your name is o."
The name Nicholas is longer than five characters, so fifthLetter
completes and returns the fifth letter in the name Nicholas, which is the letter o. Let’s try calling it again on a shorter name:
fifthLetter("Nick"); undefined
When we call fifthLetter
with the name Nick, the function knows that the name isn’t long enough, so it exits early with the first return
statement at ➋. Because there is no value specified after the return
at ➋, the function returns undefined
.
We can use multiple return
keywords inside different if
statements in a function body to have a function return a different value depending on the input. For example, say you’re writing a game that awards players medals based on their score. A score of 3 or below is a bronze medal, scores between 3 and 7 are silver, and anything above 7 is gold. You could use a function like medalForScore
to evaluate a score and return the right kind of medal, as shown here:
var medalForScore = function (score) { if (score < 3) { ➊ return "Bronze"; } ➋ if (score < 7) { return "Silver"; } ➌ return "Gold"; };
At ➊ we return "Bronze"
and exit the function if the score is less than 3. If we reach ➋ we know that score
must be at least 3, because if it was less than 3, we would have returned already (that is, we would have exited the function when we reached the return
keyword in the first test). Finally, if we reach ➌, we know that score
must be at least 7, so there’s nothing left to check, and we can just return "Gold"
.
Although we’re checking multiple conditions, we don’t need to use chained if...else
statements. We use if...else
statements to ensure that only one of the options is executed. When each of the options has its own return
statement, this also ensures that only one of the options will be executed (because functions can return only once).
Functions allow us to reuse blocks of code. They can do different things depending on the arguments passed to them, and they can return values to the location in the code where the function was called. Functions also make it possible to give a piece of code a meaningful name. For example, the name of the function pickRandomWord
makes clear that the function has something to do with picking a random word.
In the next chapter, we’ll learn how to write JavaScript that can manipulate HTML documents.
Here are some challenges for you to practice working with functions.
#1: DOING ARITHMETIC WITH FUNCTIONS
Create two functions, add
and multiply
. Each should take two arguments. The add
function should sum its arguments and return the result, and multiply
should multiply its arguments.
Using only these two functions, solve this simple mathematical problem:
36325 * 9824 + 777
#2: ARE THESE ARRAYS THE SAME?
Write a function called areArraysSame
that takes two arrays of numbers as arguments. It should return true
if the two arrays are the same (that is, they have the same numbers in the same order) and false
if they’re different. Try running the following code to make sure your functions are working correctly:
areArraysSame([1, 2, 3], [4, 5, 6]); false areArraysSame([1, 2, 3], [1, 2, 3]); true areArraysSame([1, 2, 3], [1, 2, 3, 4]); false
Hint 1: you’ll need to use a for
loop to go through each of the values in the first array to see whether they’re the same in the second array. You can return false
in the for
loop if you find a value that’s not equal.
Hint 2: you can leave the function early and skip the for
loop altogether if the arrays are different lengths.
#3: HANGMAN, USING FUNCTIONS
Go back to your Hangman game from Chapter 7. We’re going to rewrite it using functions.
I’ve rewritten the final Hangman code here, but with certain parts of the code replaced by function calls. All you need to do is write the functions!
// Write your functions here var word = pickWord(); var answerArray = setupAnswerArray(word); var remainingLetters = word.length; while (remainingLetters > 0) { showPlayerProgress(answerArray); var guess = getGuess(); if (guess === null) { break; } else if (guess.length !== 1) { alert("Please enter a single letter."); } else { var correctGuesses = updateGameState(guess, word, answerArray); remainingLetters -= correctGuesses; } } showAnswerAndCongratulatePlayer(answerArray);
This version of the code using functions is almost as simple as the pseudocode version from Chapter 7. This should give you some idea of how useful functions can be for making code easier to understand.
Here are the functions you need to fill in:
var pickWord = function () { // Return a random word }; var setupAnswerArray = function (word) { // Return the answer array }; var showPlayerProgress = function (answerArray) { // Use alert to show the player their progress }; var getGuess = function () { // Use prompt to get a guess }; var updateGameState = function (guess, word, answerArray) { // Update answerArray and return a number showing how many // times the guess appears in the word so remainingLetters // can be updated }; var showAnswerAndCongratulatePlayer = function (answerArray) { // Use alert to show the answer and congratulate the player };
3.147.77.208