Declaring & calling functions
Learn how JavaScript function declarations package reusable code, receive arguments through parameters, return values, and work with local and outer variables.
- 01Write and call a functionWrite a function declaration, call it, and say when its steps run.
- 02Pass values in and get one backTell parameters from arguments. Use
returnto give a value back, not just print it. - 03Know which names a function can useExplain local and outer variables and shadowing, and give functions clear names.
What a function is
A function is a group of steps with a name. You write the steps once. Then you can run them as many times as you like. Running a function is called calling it.
Without functions, you would copy the same five lines into ten places. With a function, you write those lines once and call the function ten times.
In the Thinking like a developer lesson, you split a problem into small jobs with names like addTip and splitBill. This lesson shows how to write those jobs in JavaScript. You will learn:
- How to write a function and how to call it.
- How to pass values into a function.
- How to get a value back out with
return. - Which variables a function can use.
function greet(user) {
return "Hello, " + user;
}
console.log(greet("Asha"));Lines 1–3 write a function called greet. JavaScript does not run its steps yet. Line 5 calls greet with the value "Asha". The function gives back the text Hello, Asha, and line 5 prints it.
"Asha" goes in. The function runs its steps. One new value, "Hello, Asha", comes back out.A function is a set of steps with a name. It can take values in. It can give one value back with return.
Writing a recipe card does not cook dinner. The card only keeps the steps for later. When you want food, you cook from the card. Writing a function is like writing the card. Calling the function is like cooking one dish from it.
- In real life: The recipe's title
- In JavaScript: The function's name, like
makeGreeting - In real life: A blank on the card: “___ cups of flour”
- In JavaScript: A parameter, written with the function
- In real life: What you fill in today: “2 cups”
- In JavaScript: An argument, given in one call
- In real life: The finished dish
- In JavaScript: The value the function gives back
Remember this: the steps inside a function do not run when JavaScript reads them. They wait. They run only when some code calls the function.
Function declarations
STEP THROUGHThe usual way to write a function is a function declaration. It has four parts, in this order:
- The word
function. - A name, like
nameHere. - Round brackets
(). They hold names for the values the function takes in. These names are called parameters. You'll meet them in the next section. - Curly braces
{ }. They hold the steps. These steps are called the function's body.
function nameHere(parameterHere) { // steps go here return valueHere;}The name should say what the function does. The return line is optional. You'll learn what it does in the "Returning values" section.
function sayHi() {
console.log("Hi");
}
console.log("Ready");
sayHi();Lines 1–3 make the function sayHi. They don't print anything yet. Line 5 prints Ready. Line 6 calls sayHi, so now its body runs and prints Hi. That's why Ready comes first.
The replay below runs real code, one step at a time. First, guess what line 7 prints. Then press Step. Watch where it starts: it skips lines 1–4 and starts at line 6, the call.
The function's steps wait until line 6 calls it. Pick a name and guess the greeting. Then step through the call and the return.
script
function makeGreeting(name) { const message = "Hello, " + name + "!"; return message;} console.log(greeting);Here is what happens, in order:
- Line 6 calls
makeGreetingwith a name. - Inside the function,
namegets that value. - Line 2 builds the greeting and keeps it in
message. - Line 3 gives
messageback to line 6. - Line 6 keeps that value in
greeting. - Line 7 prints
greeting.
You can call a function declaration on a line above the place where you wrote it. Before JavaScript runs the code in a file or a function, it first sets up every function declaration written there. This is called hoisting. The Hoisting & the temporal dead zone lesson explains the full rules later.
console.log(sayHi()); function sayHi() { return "Hi before the declaration line";}Line 1 calls sayHi before line 3 writes it. It still works, and it prints Hi before the declaration line.
Parameters and arguments
INTERACTIVEA function can take values in. Two words describe this, and they are easy to mix up:
- A parameter is a name in the round brackets of the declaration, like
nameinfunction greet(name). It is an empty spot that waits for a value. - An argument is the value you put in the round brackets of a call, like
"Maya"ingreet("Maya"). It fills that spot for this one call.
The table below sums this up. Read each row as: "this word means this, and you see it here."
| Word or rule | Where you see it | What it means |
|---|---|---|
| Parameter | In the declaration: function greet(name) | A name that waits for a value. Each call fills it. |
| Argument | In the call: greet("Maya") | The real value this one call gives the function. |
| Same number of each | total(price, tax) called as total(20, 3) | The first argument goes to the first parameter, the second to the second, and so on. |
| A different number | A call with too few or too many values | A parameter with no value gets undefined. This function ignores the extra values. |
function welcome(user) {
return "Welcome, " + user;
}
console.log(welcome("Asha"));
console.log(welcome());Line 5 calls welcome with the argument "Asha". So the parameter user gets "Asha", and the line prints Welcome, Asha.
Line 6 calls welcome with nothing in the brackets. So user gets undefined, the value JavaScript uses for "nothing here". The line prints Welcome, undefined.
user is like an empty box inside the function. Each call fills it. welcome("Asha") puts "Asha" in. welcome() passes nothing, so the box holds undefined.Now try it yourself. The function below has two parameters, item and quantity. Each button picks a call with a different number of arguments: zero, one, two, or three. The right side shows the value each parameter gets.
function describeOrder(item, quantity) { return "item=" + item + ", quantity=" + quantity;} console.log(describeOrder());console.log(describeOrder("tea"));console.log(describeOrder("tea", 2));console.log(describeOrder("tea", 2, "ignored"));- item getsundefinedquantity getsundefinedthe call gives backitem=undefined, quantity=undefined
No arguments, so both parameters get undefined. undefined is the value JavaScript uses for “nothing was given”.
A parameter with no matching argument gets undefined. An extra argument is still passed to the function. But this function has no third parameter, so nothing uses the third value. The next lesson, Default & rest parameters, shows how to collect extra values on purpose. It also covers the older arguments object.
nameinfunction greet(name) {}"Maya"ingreet("Maya")priceandtaxinfunction total(price, tax)20, 3intotal(20, 3)quantityinfunction describeOrder(item, quantity)- The third value in
describeOrder("tea", 2, true)
Is it a name in the declaration (a parameter) or a value in a call (an argument)? Sort each card.
Returning values
INTERACTIVEreturn gives one value back to the code that called the function. That value is called the return value. As soon as return runs, the function stops.
Returning a value is not the same as printing it:
console.logshows a value on the screen. Your code can't use that shown value again.returnhands the value back to the call. Your code can keep it in a variable, add to it, or print it.
So a function that works out a number should usually return it. The code that called the function can then decide what to do with it.
function double(number) {
return number * 2;
}
const score = double(3);
console.log(score + 1);Line 5 calls double(3). Inside the function, line 2 returns 6. Line 5 keeps that 6 in score. Line 6 adds 1 and prints 7. If the function had only printed 6, line 6 would have no number to add to.
console.log only shows a value on the screen. Your code can't use it again. return hands the value back to the call, so line 5 can keep it in score and use it later.The playground below has three small functions. Pick a button to see what each one gives back.
let checks = 0; function logTotal(price, tax) { const total = price + tax; console.log(total);} function returnTotal(price, tax) { const total = price + tax; return total;} function isAllowed(age) { checks = checks + 1; if (age < 18) return false; checks = checks + 1; return true;}- the console showed23the call gives backundefined
logTotal prints 23 on line 5. But it has no return, so the call gives back undefined. The printed 23 can't be used again.
The three cards below sum up what a call gives back.
The call gives back undefined. This is true even if the function printed something while it ran.
The call gives back the returned value. Other code can keep it and use it.
A return inside an if can stop the function before its later lines run.
You have seen undefined in earlier lessons. It means "no value here". A function that never reaches a return gives back undefined too.
Local & outer variables
STEP THROUGHA function can use two kinds of variables:
- A local variable is made inside the function. Its parameters are local too. Only code inside the function can use them. Each call gets a fresh set.
- An outer variable is made outside the function, in the code around it. The function can read it and change it.
function makeLabel() {
const label = "Save";
return label;
}
console.log(makeLabel());Line 2 makes a local variable, label. Only code inside makeLabel can use it. Line 3 returns its value. So line 6 gets the text and prints Save.
This is a good pattern to copy: values go in through parameters, and one value comes out through return.
A cook works with bowls on their own counter. Nobody else uses those bowls. The cook can also take things from the shared pantry. Now say the cook labels one bowl "pantry". When the cook says "pantry", they now mean the bowl, not the shelves.
- In real life: Bowls on the cook's own counter
- In JavaScript: Local variables inside one call
- In real life: The shared pantry shelves
- In JavaScript: Outer variables that nearby code can use
- In real life: A bowl on the counter labelled “pantry”
- In JavaScript: A local name that hides an outer name
- In real life: Taking sugar from the shared jar
- In JavaScript: Changing an outer variable
The next replay has both kinds of variables. It also shows shadowing: a local variable with the same name as an outer one. Inside its area, the local one hides the outer one.
Look at lines 6–10. They sit inside an extra pair of curly braces, called a block. Line 7 makes a new pantry that lives only inside that block. Line 5 runs before the block, so it still sees the outer pantry.
Step through local variables, outer variables, and a local name that hides an outer one. This replays the example code one step at a time. It is not the browser's debugger.
script
let scoops = 0; function bake(label) { const localBowl = label + " uses " + pantry; { let pantry = "cocoa"; scoops = scoops + 1; return localBowl + "; local pantry is " + pantry; }} const result = bake("cake");console.log(result);console.log(scoops);The table below lists each kind of name in that replay. Read each row as: "this kind of name, for example this one, works like this."
| Kind of name | Example | What to remember |
|---|---|---|
| Local | const localBowl inside bake | It is made for this call. Code outside the function can't use it. |
| Parameter | label in function bake(label) | It is local too. It gets the argument of this call. |
| Outer | let scoops = 0 above the function | The function can read it and change it. |
| Shadowing | A local pantry while an outer pantry exists | Inside its block, the local pantry hides the outer one. The outer one doesn't change. |
The next code tries to use a local variable from outside its function. It fails on purpose.
function wrapGift() { const ribbon = "blue"; return ribbon;} wrapGift();console.log(ribbon);Line 2 makes the local ribbon inside wrapGift. Line 7 is outside the function, and there is no ribbon out there. So line 7 throws a ReferenceError, the error JavaScript gives when it can't find a name. If outside code needs the value, return it.
ribbon is made inside wrapGift, so only code inside the function can use it. Outside, there is no box called ribbon, so line 7 throws a ReferenceError.labelinfunction bake(label)const localBowl, made insidebakescoops, made abovefunction bake- The first
pantry, made above the function let pantry = "cocoa"insidebakeresult, made below the call tobake
Each card names a variable from the bake example. Is it local to bake, or outer? Sort each card.
Naming functions
STYLEA function does something, so its name usually starts with a verb, a doing word like format, calculate, or get. You met this habit in the Coding style & naming lesson. It matters most for functions. With a good name, a reader knows what a call does without reading the function's body.
function formatPrice(price) {
return "$" + price;
}
function isFree(price) {
return price === 0;
}
console.log(formatPrice(3));
console.log(isFree(3));formatPrice says it turns a price into text to show. isFree reads like a yes-or-no question: "is it free?" Line 9 prints $3. Line 10 prints false.
The table below compares good and vague names. Read each row as: "for this job, use this name, because of this, and not that vague name."
| The job | Good name | Why it works | Vague name |
|---|---|---|---|
| Add up a cart | calculateTotal | A verb, then the thing it gives back. | total |
| Check an email address | isValidEmail | It reads like a yes-or-no question. | check |
| Get a saved user | getUser | It says what value comes back. | data |
| Turn cents into price text | formatPrice | It says how the value changes. | makeNice |
Give each function one job. Say you want to name a function calculateAndPrintAndSaveTotal. That name is a sign to split it into smaller functions: one to calculate, one to print, and one to save.
A function that returns true or false often starts with is, has, or can: isValidEmail, hasDiscount, canCheckout. Then if (canCheckout(cart)) reads almost like a sentence: "if you can check out the cart".
Where you’ll use functions
Real programs are full of functions. You use them to:
- Write a repeated job once.
- Give a small idea a clear name.
- Test one piece of code on its own.
function calculateSubtotal(items) { return items.length * 10;} function addTip(total, rate) { return total + total * rate;} function formatReceipt(name, total) { return name + " owes $" + total;} const subtotal = calculateSubtotal(["tea", "cake"]);const withTip = addTip(subtotal, 0.2);console.log(formatReceipt("Maya", withTip));Lines 1, 5, and 9 each start a small function with one job. Follow the values from line 13 down:
- Line 13 passes two items to
calculateSubtotal. Each item costs 10, so it returns20. - Line 14 passes
20and a 20% tip rate toaddTip. It returns24. - Line 15 passes
"Maya"and24toformatReceipt, then printsMaya owes $24.
Each function takes values in and returns one value. Each result is kept in a variable for the next step. This makes bugs easier to find. In the browser's debugger, you can step into a function to see its local variables. Or you can step over it when its name already tells you enough.
The total and the receipt text are made by separate functions. So a form can use the total without making receipt text too.
You will also see functions that run when a user clicks a button, that check what a user typed, and that turn values into text. Later lessons in this module show more ways to write and use functions: Default & rest parameters, Function expressions & callbacks, Arrow functions, and Recursion.
Common misconceptions
WATCH OUT- “A declaration runs its steps right away.” It doesn't. The steps run only when you call the function.
- “Parameter and argument mean the same thing.” A parameter is the name in the declaration. An argument is the value in a call.
- “Printing a value returns it.” Printing only shows the value on the screen. Only
returngives it back to the call. - “Every function gives back a value you can see.” A function with no
returngives backundefined. - “A local variable still exists after the call.” Code outside the function can never use it.
- “The same name means the same variable.” A local variable can have the same name as an outer one. It hides the outer one but doesn't change it.
When a function prints something you didn't expect, look at the call first. Ask three questions:
- Which arguments went in?
- Did the function return a value?
- Did it change an outer variable?
The Reading error messages and Debugging in the browser lessons help here too. Both error messages and the debugger show which functions were called.
Practice exercises
5 EXERCISESWrite a function declaration called rectangleArea. Give it two parameters, width and height. Make it return the area. Then call it with 5 and 4, and print the result.
function rectangleArea(width, height) {
// return the area
}
console.log(rectangleArea(5, 4));function rectangleArea(width, height) {
return width * height;
}
console.log(rectangleArea(5, 4));The call rectangleArea(5, 4) gives width the value 5 and height the value 4. return width * height gives back 20. The last line prints it.
What does the last line print? Don't give the value of result inside the function. Give the value that the call double(4) gives back.
function double(number) {
const result = number * 2;
}
console.log(double(4));The function ends without a return, so the call double(4) gives back undefined. JavaScript doesn't return result for you.
Right now the code prints 10 and then NaN ("not a number"). That's because tip is undefined. Change the function so the last line prints 20.
function getTip(total) {
console.log(total * 0.2);
}
const tip = getTip(50);
console.log(tip + 10);function getTip(total) {
return total * 0.2;
}
const tip = getTip(50);
console.log(tip + 10);Now getTip(50) returns 10. Line 5 keeps it in tip. Line 6 adds 10 and prints 20.
Write the two lines the console prints, in order. This checks whether a local variable changes an outer variable with the same name.
let label = "outer";
function printLabel() {
let label = "inner";
console.log(label);
}
printLabel();
console.log(label);Line 5 prints the local label, so the first line is inner. Line 9 is outside the function and prints the outer label, so the second line is outer.
You need a function that takes the items in a cart and returns their total price. Type a good name for it. More than one clear name is accepted.
calculateTotalcalculateTotal starts with a verb. It tells readers that the function works out a total and returns it. It doesn't sound like a stored piece of data.
Quiz
8 QUESTIONSFor each code question, follow these steps:
- Find each function declaration. Its steps wait.
- Find each call. Put the arguments into the parameters.
- Follow the
returnto see what the call gives back. - Remember that local variables stay inside their function.
Question 1 of 8When JavaScript reads a function declaration, what does the declaration do?
Choose an answer to see the explanation.
Question 2 of 8What does the
add(2, 5)call print?Read the code, then predictfunction add(a, b) { return a + b; } console.log(add(2, 5));Choose an answer to see the explanation.
Question 3 of 8In
function greet(name) {}and the callgreet("Ari"), which one is the argument?Choose an answer to see the explanation.
Question 4 of 8What is the last line this code prints?
Read the code, then predictfunction show(value) { console.log(value); } const result = show("hi"); console.log(result);Choose an answer to see the explanation.
Question 5 of 8A function runs
return. What happens to the lines after it in the same function?Choose an answer to see the explanation.
Question 6 of 8Two variables share the name
word. What two lines does this code print?Read the code, then predictlet word = "outer"; function sayWord() { let word = "inner"; return word; } console.log(sayWord()); console.log(word);Choose an answer to see the explanation.
Question 7 of 8Which name is best for a function that checks whether an email address is valid?
Choose an answer to see the explanation.
Question 8 of 8This code calls
sayHiabove its declaration. What does it print?Read the code, then predictconsole.log(sayHi()); function sayHi() { return "hi"; }Choose an answer to see the explanation.
Key takeaways
- A function declaration gives a set of steps a name. A call runs those steps.
- Parameters are the names in the declaration. Arguments are the values in a call.
returngives one value back to the call and stops the function.- A function with no
returngives backundefined. - Local variables live inside the function. Outer variables live around it, and the function can read and change them.
- A good function name starts with a verb and describes one job.
In one line: a function is a named set of steps. It can take values in, use its own local variables, and give one value back.
Up next: Default & rest parameters.