Function Declarations
A function declaration is the most fundamental way to package a block of logic under a name so you can run it whenever you like. Instead of repeating the same steps, you write them once, give them a name, and call that name with different inputs. Declarations are also the only function form that JavaScript fully hoists, which gives them a unique behaviour worth understanding early.
Declaration syntax
A function declaration starts with the function keyword, followed by a name, a parenthesised list of parameters, and a body in curly braces. The name becomes a variable in the surrounding scope that holds the function.
function greet(name) {
return `Hello, ${name}!`;
}
The pieces are:
| Part | Example | Role |
|---|---|---|
| Keyword | function | Marks the start of a declaration |
| Name | greet | The identifier you call later |
| Parameters | (name) | Named inputs, available inside the body |
| Body | { ... } | The statements that run on each call |
Because greet is a declaration (a statement on its own, not assigned to a variable), it is hoisted — more on that below.
Calling functions
Defining a function does nothing on its own; the body only runs when you call (invoke) it by writing its name followed by parentheses. Any values you pass inside the parentheses become the arguments bound to the parameters.
function add(a, b) {
return a + b;
}
console.log(add(2, 3));
console.log(add(10, -4));
Output:
5
6
You can call the same function as many times as you want with different arguments. Each call gets its own fresh set of parameter values and its own local scope.
Parameters and return values
Parameters are placeholders listed in the definition; arguments are the actual values supplied at the call site. The return statement sends a value back to the caller and immediately ends the function — any code after a reached return does not run.
function classify(score) {
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
return "F";
}
console.log(classify(95));
console.log(classify(72));
console.log(classify(40));
Output:
A
C
F
A function with no return, or a bare return;, hands back undefined. This is normal for functions that exist for their side effects, such as logging or updating the DOM.
function logBanner(text) {
console.log("=".repeat(text.length));
console.log(text);
console.log("=".repeat(text.length));
}
const result = logBanner("DevCraftly");
console.log(result);
Output:
==========
DevCraftly
==========
undefined
A function can only return a single value. To return several pieces of data, bundle them into an object or array and destructure them at the call site:
const { min, max } = bounds(list).
Hoisting
Function declarations are hoisted: the engine registers them during the compile phase, before any line of code executes. This means you can call a declared function on a line above where it is written.
console.log(square(5));
function square(n) {
return n * n;
}
Output:
25
This is the key behavioural difference between declarations and function expressions (functions assigned to a const or let). Expressions are not hoisted as callable values, so calling them before their definition throws a ReferenceError. Hoisting lets you organise a file with high-level logic at the top and helper functions below it.
Hoisting applies to the function body too, not just the name. But do not rely on it to call a function before its declaration across module boundaries or inside blocks — keep call order readable.
Functions calling functions
Functions become powerful when they compose. One function can call another, building larger behaviour from small, testable pieces.
function toCents(dollars) {
return Math.round(dollars * 100);
}
function formatPrice(dollars) {
const cents = toCents(dollars);
return `$${(cents / 100).toFixed(2)}`;
}
console.log(formatPrice(19.5));
console.log(formatPrice(3.999));
Output:
$19.50
$4.00
Each helper does one job, and formatPrice orchestrates them. This is the foundation of clean, maintainable JavaScript.
Best Practices
- Name functions with descriptive verbs (
calculateTotal,fetchUser) so call sites read like plain English. - Keep each function focused on a single responsibility; if it does two things, split it.
- Always
returna value from functions meant to produce results, and lean on early returns to flatten nested conditionals. - Prefer a small, fixed parameter list; pass an options object once you exceed three or four parameters.
- Rely on hoisting for readability (helpers below, high-level logic on top), but never to obscure execution order.
- Avoid mutating arguments passed in; return new values so callers stay in control of their data.