Declaring & calling functions
Learn how JavaScript function declarations package reusable code, receive arguments through parameters, return values, and work with local and outer variables.
- 01Declare and call a functionRead a function declaration, call it, and trace when the body actually runs.
- 02Pass input and return outputDistinguish parameters from arguments and use return instead of only printing.
- 03Reason about namesExplain local variables, outer variables, shadowing, and beginner-friendly function names.
Functions are reusable recipes
A function is a block of JavaScript you can give a name, then run whenever you need it. Instead of copying the same five lines into ten places, you write the steps once and call the function ten times.
You already met small helpers in Thinking like a developer: names like addTip and splitBill turn a messy problem into little jobs. This lesson gives those jobs their JavaScript shape: function declarations, parameters, arguments, return, and the variables that live inside or around a function.
A function packages code behind a name, can receive input through parameters, and can hand one result back with return.
Writing the recipe card does not cook dinner. It stores the steps so a cook can use them later. A function declaration is the recipe card; a function call is the moment you ask the cook to make one serving.
- In real life: Recipe title
- In JavaScript: Function name, like
makeGreeting - In real life: Blanks on the card: “___ cups of flour”
- In JavaScript: Parameters in the declaration
- In real life: What you put in today: “2 cups”
- In JavaScript: Arguments in one call
- In real life: The finished dish handed through the window
- In JavaScript: The return value
Where the analogy stops: A recipe can be followed by a patient human who improvises. JavaScript follows the function exactly: misspell a name or forget a return value and you get the real language behavior, not a helpful guess.
Keep that separation in mind. New learners often stare at a function body and expect it to run from top to bottom immediately. It does not. The body waits until a call presses the button.
Function declarations
STEP THROUGHA function declaration starts with the keyword function, then a name, parentheses, and a block:
function nameHere(parameterHere) { // steps go here return valueHere;}The name should tell readers what the block does. The parentheses hold input names. The braces hold the steps that run later. The return line is optional, but without it the call value is undefined.
The next replay is recorded from real functions in this lesson. First, predict what line 7 prints. Then step through the call. Notice that JavaScript does not step into lines 1–4 until line 6 calls the function.
A function declaration is skipped until you call it. Change the name, predict the greeting, then step through the call and return.
script
function makeGreeting(name) { const message = "Hello, " + name + "!"; return message;} console.log(greeting);The important events are: line 6 calls makeGreeting, the parameter name receives the argument, line 2 creates a local message, line 3 returns it, and line 6 stores the returned value in greeting. Finally line 7 prints a value that was already returned.
A function declaration can be called before its line in the same scope. That is called hoisting. This lesson uses the fact gently; the deeper Hoisting & the temporal dead zone lesson explains the full rule later.
sayHi(); function sayHi() { return "Hi before the declaration line";}Parameters vs arguments
INTERACTIVEThe two words are easy to mix up because they point at the same flow of data from different sides.
| Word | Where you see it | Plain meaning |
|---|---|---|
| Parameter | In the declaration: function greet(name) | The blank the function promises to fill for each call. |
| Argument | In the call: greet("Maya") | The actual value supplied today. |
| Same count | total(price, tax) and total(20, 3) | Arguments line up with parameters from left to right. |
| Different count | Missing or extra values | Missing parameters become undefined; extra values are ignored here. |
Try the calls below. The function has exactly two parameter names, but the call can provide zero, one, two, or three arguments. The output pane shows the actual local values JavaScript gives to the parameters.
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 parameterundefinedquantity parameterundefinedreturned textitem=undefined, quantity=undefined
No arguments means both parameters receive undefined. That is a real value meaning “nothing was provided”.
Missing arguments become undefined. Extra arguments are still passed to the call, but this function has no parameter name for the third one, so it does not use it. JavaScript has an older arguments object and modern rest parameters for collecting extras on purpose; those are the focus of the next lesson, Default & rest parameters.
nameinfunction greet(name) {}"Maya"ingreet("Maya")priceandtaxinfunction total(price, tax)20, 3intotal(20, 3)quantityindescribeOrder(item, quantity)- The third value in
describeOrder("tea", 2, true)
Sort each card by whether it names a blank in the declaration or a value in a call.
Returning values
INTERACTIVEreturn is the kitchen window. The function has been doing work on its own counter; return hands one finished value back to whoever called it. Once that happens, the current call stops.
Returning is not the same as printing. console.log is a useful way to inspect a value, but it does not make that value reusable by the caller. A calculation helper should usually return the number it calculated, then the caller decides whether to print it, store it, or combine it with something else.
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;}- console printed23call valueundefined
logTotal prints 23, but its call value is undefined because it has no return statement. Printing is a side effect, not reusable output.
The call value is undefined, even if the function printed something while it ran.
The call expression becomes the returned value, so other code can reuse it.
A return inside an if can end a call before later lines run.
You saw undefined in earlier lessons when the console had no useful expression value to show. Functions use the same value when no explicit return happens.
Local & outer variables
STEP THROUGHEvery function call gets its own little workspace. Parameters and variables declared inside the function are local to that call. Code outside cannot use those local names. A function can also read variables from the surrounding code; those are outer variables.
A cook can use a private bowl while also reaching into a shared pantry. If the cook labels a bowl “pantry,” that label hides the shared shelf name while the cook is looking at the bowl.
- In real life: Ingredients on the cook’s counter
- In JavaScript: Local variables inside one call
- In real life: Shared pantry shelves
- In JavaScript: Outer variables nearby code can use
- In real life: A bowl named pantry on the counter
- In JavaScript: A local name shadowing an outer name
- In real life: Changing the shared sugar jar
- In JavaScript: Mutating an outer variable
Where the analogy stops: Real kitchens have people negotiating over shared shelves. JavaScript follows lexical lookup rules exactly; the deeper Scope & lexical environments lesson explains the full search path later.
Step through local variables, an outer variable, and a shadowed name. This is a guided replay of this example, not a 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);| Kind | Example | What to remember |
|---|---|---|
| Local | const localBowl inside bake | Created for this call; not visible outside the function. |
| Parameter | label in function bake(label) | Also local; it receives one argument for this call. |
| Outer | let scoops = 0 before the function | The function can read or change it. |
| Shadowed | A local pantry when an outer pantry exists | The inner name wins only in its local area. |
function wrapGift() { const ribbon = "blue"; return ribbon;} wrapGift();console.log(ribbon);That last snippet throws a ReferenceError at line 7. The local ribbon existed while wrapGift was running, but outside code never gets a variable with that name. Return the value if outside code needs it.
labelinsidefunction bake(label)const localBowldeclared insidebakescoopsdeclared beforefunction bake- The first
pantrydeclared before the function let pantry = "cocoa"insidebakeresultdeclared after callingbake
Sort each name by where it lives in the scope example.
Naming functions
STYLEFunctions do things, so their names usually start with verbs. The Coding style & naming lesson introduced this habit; functions make it especially valuable because a good name lets readers understand a call without opening the body.
| Goal | Good name | Why it works | Vague name |
|---|---|---|---|
| Calculate a cart total | calculateTotal | Verb + thing returned | total |
| Check an email | isValidEmail | Reads like a yes/no question | check |
| Fetch a saved user | getUser | Says what value comes back | data |
| Format cents for display | formatPrice | Names the transformation | makeNice |
Prefer one job per function. If you are tempted to name something calculateAndPrintAndSaveTotal, split it. One function can calculate; another can print; a later lesson on callbacks shows how to pass functions around when jobs need to be connected.
Boolean-returning functions often read well with prefixes like is, has, or can: isValidEmail, hasDiscount, canCheckout. That makes if (canCheckout(cart)) read like a sentence.
Where you’ll use functions
Functions are everywhere once a program grows beyond a few lines. You use them to isolate repeated work, to name a small idea, and to test a piece of logic without clicking through the whole app.
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));Notice the data flow: values go in as arguments, each function returns one value, and the script stores the returned values for the next step. That pattern makes debugging easier. In the browser debugger you can step into a function to see its local variables, or step over it when the name already tells you enough.
Functions also appear as event handlers, validation helpers, formatters, and small calculations. Later in this module, Default & rest parameters, Function expressions & callbacks, Arrow functions, and Recursion add more ways to shape and use them.
Common misconceptions
WATCH OUT- “A declaration runs immediately.” It does not. A call runs the body.
- “Parameters and arguments are the same word.” They describe different sides of the same handoff.
- “Printing returns the value.” Printing is a side effect;
returncreates the call value. - “Every function returns something visible.” A function with no return gives
undefined. - “A local variable exists after the call.” Local names disappear from outside code when the call ends.
- “Same name means same variable.” A local name can shadow an outer name without changing it.
When output surprises you, read the call site first. What 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 are useful companions here because stack traces and step controls both show function calls.
Practice exercises
5 EXERCISESWrite a function declaration named rectangleArea with two parameters, width and height. Return the area, then call it with 5 and 4.
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 parameters width and height receive 5 and 4. return width * height makes the call value 20, and the final line prints it.
Predict the exact value printed by the last line. Do not answer what result was inside the function; answer the call value.
function double(number) {
const result = number * 2;
}
console.log(double(4));The function finishes without a return statement, so the call double(4) has the value undefined. The local result is not automatically returned.
The starter code prints 10 and then NaN because tip is undefined. Change the helper so the final 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);Returning the tip makes getTip(50) evaluate to 10. The caller stores that in tip, adds 10, and prints 20.
Write the two console lines in order. This checks whether a local variable with the same name changes the outer one.
let label = "outer";
function printLabel() {
let label = "inner";
console.log(label);
}
printLabel();
console.log(label);The function logs the local label, so the first line is inner. After the call, the script logs the outer label, so the second line is outer.
You need a function that receives cart items and returns the total price. Type a good function name. Several clear verb phrases are accepted.
calculateTotalcalculateTotal is a clear verb phrase. It tells readers the function computes and returns a total, not that it stores a piece of data.
Quiz
8 QUESTIONSRead each snippet like a trace: declarations wait, calls fill parameters with arguments, return hands a value back, and local names stay inside their call.
Question 1 of 8What does a function declaration do when JavaScript first reaches it in this lesson’s examples?
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) {}andgreet("Ari"), which word is the argument?Choose an answer to see the explanation.
Question 4 of 8What does the
show("hi")example print last?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 8What happens to code after
returnin the same function call?Choose an answer to see the explanation.
Question 6 of 8What two lines does the shadowing example 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 best matches a function that checks whether an email string is valid?
Choose an answer to see the explanation.
Question 8 of 8What does the hoisted
sayHiexample print?Read the code, then predictconsole.log(sayHi()); function sayHi() { return "hi"; }Choose an answer to see the explanation.
Key takeaways
- A function declaration names a reusable block; a call runs it.
- Parameters are blanks in the declaration; arguments are values in a call.
returncreates the call value and stops the current call.- Without an explicit return value, a function call gives
undefined. - Local variables live inside a call; outer variables live around it and can be read or changed.
- Good function names are clear verb phrases and usually describe one job.
Final definition: a function is a named, reusable set of steps that can receive arguments, work with local variables, and return one value to its caller.
Up next: Default & rest parameters.