JAVASCRIPT / FUNCTIONS
Defining and calling functions
Declare a named function, call it as many times as you need, and tell the difference between a function's name and a call to that function.
What you will learn
- Write a declaration: the function keyword, a name, a parameter list, and a braced body.
- Run a body by putting () after the name; the bare name only refers to the function.
- Call one definition as many times as you like, each call with fresh local variables.
- Read a call as a pause: the caller waits until the body finishes, then resumes.
Understanding Defining and calling functions
A function declaration is a statement that does two things at once: it creates a binding with the name you wrote, and it stores a block of code as that binding's value. Writing function shout(word) { ... } puts a function object in shout, and the statements between the braces are recorded rather than executed. A file containing nothing but declarations produces no output at all, which is the first thing to check when a script appears to do nothing.
The parentheses in shout('hello') are the call operator, and they are the only thing that makes the body run. JavaScript evaluates the expression to the left of them, checks that the result is callable, evaluates the arguments, then executes the stored statements from the top of the body. Written alone, shout is a legal expression that produces the function object and throws it away, which is exactly why a callback is handed to another function as shout and never as shout().
A workable mental model is that a definition is inert and a call is one live run of it. Every call gets its own parameters and its own local variables, so separate runs cannot contaminate each other, and the caller stops at the call site until the body finishes and control returns to the next statement. Because the body lives under a name, one definition serves any number of calls from any number of places, and that reuse is the reason to define a function instead of repeating statements.
function shout(word) {
console.log(word.toUpperCase() + '!');
}
shout('hello');
shout('again');
shout; // an expression, not a call: nothing runs
console.log(typeof shout);Defining a function stores a body under a name; the parentheses in a call are what actually run that body.
Worked examples
The name and the call are different things
Shows that a function name is a value you can copy, while parentheses are what execute the body.
function tick() {
console.log('tick');
}
const alias = tick; // no parentheses: copies the reference
alias(); // parentheses: runs the body
const result = tick();
console.log(result);
console.log(alias === tick);Example explained
Line 1const alias = tick; stores a reference to the same function object; with no parentheses, nothing executes on this line.
Line 2alias(); applies the call operator to that reference, so the stored body runs and prints tick.
Line 3const result = tick(); runs the body a second time, and the call finishes as a value that is undefined because this body never hands one back.
Line 4alias === tick is true because the assignment copied one reference, it did not make a second copy of the body.
Calls transfer control and give it back
Demonstrates the order in which statements run when one function calls others.
function heading(text) {
console.log('== ' + text + ' ==');
}
function line(text) {
console.log(text);
}
function page() {
heading('Report');
line('All systems normal.');
heading('End');
}
page();
console.log('after page()');Example explained
Line 1page(); moves control into page's body, so the top-level line below it is suspended and does not run yet.
Line 2Each inner call runs to completion before the next statement of page starts, which is why the three lines come out in source order.
Line 3heading is defined once but called twice with different arguments, producing two differently worded lines from one body.
Line 4When page's last statement finishes, control returns to the call site and the final top-level line prints.
Every call starts with clean locals
Shows that variables declared inside the body are created fresh for each call.
function countdown(from) {
let n = from;
let out = '';
while (n > 0) {
out += n + ' ';
n = n - 1;
}
console.log(out + 'go');
}
countdown(3);
countdown(5);Example explained
Line 1let n = from; creates a new binding on each call, so the second call starts at 5 with no memory of the first.
Line 2The while loop mutates only this call's n and out, which is why out does not accumulate across calls.
Line 3After console.log runs, the call ends and both locals are discarded, leaving the definition unchanged for the next call.
Important notes
Parentheses are required even when a function takes no parameters: reset just evaluates to the function object, only reset() executes it.
Calling a declared function from a line above its definition works because the name is bound before the code starts running; the declaration-versus-expression lesson covers why that is not true of every way of making a function.
Common mistakes
Expecting the body to run where it is written: a script full of declarations prints nothing, and beginners conclude the code is broken when it was simply never called.
Mixing up name and call at the boundary with other APIs, such as setTimeout(save(), 1000): that runs save immediately and schedules its undefined result, while setTimeout(save, 1000) is what actually delays the run.
Declaring two functions with the same name in one scope: the later declaration silently replaces the binding, so every call anywhere runs the second body and the first one becomes unreachable.
Try it yourself
Change, predict, then run
In a browser console, declare banner(text) so it logs a row of dashes, then the text, then another row of dashes, and call it with three different strings without touching the body. Then add a line containing only banner; and confirm that nothing extra is printed.
Open the JavaScript workspaceCheck your understanding
How many times does this print ping? function ping() { console.log('ping'); } ping; const p = ping; p();
- Once
- Twice
- Not at all
- It throws a TypeError because p is not a function
Show answer
The line ping; is an expression statement: JavaScript evaluates the name to the function object and discards it, because only the call operator runs a body. p() then executes that same body once, so ping is printed a single time. Twice is tempting if you read the bare name as a call, and the TypeError option assumes assignment somehow unwraps the function, but p holds exactly the same callable object that ping does.