JavaScript Basics #4 Functions
After #3 Control Flow covered branching and looping, this post is about the tool for making reusable code units: JavaScript functions.
Function Declaration #
The most traditional form.
function add(a, b) {
return a + b;
}
add(2, 3); // 5
Starts with the function keyword and has a name. The biggest characteristic is hoisting (covered shortly) — so it works no matter where in the code you call it.
Function Expression #
A form that treats functions as values.
const add = function(a, b) {
return a + b;
};
add(2, 3); // 5
The function keyword sits on the right side of the expression. The function is stored in the variable add — it follows variable rules (block scope, no hoisting).
Arrow Function #
A short form added in ES2015. Used very often for short callbacks.
const add = (a, b) => a + b;
const square = (n) => n * n;
const greet = (name) => {
console.log(`hi, ${name}!`);
};
add(2, 3); // 5
square(5); // 25
greet('Curtis');Syntax summary:
- If the body is a single expression, the
{ return ... }can be omitted - If there’s one parameter, parentheses can be omitted (
n => n * 2) - If there are zero or two-plus parameters, parentheses are required
Difference between arrow and regular functions — this
#
The biggest difference is how this behaves. A regular function’s this depends on how it’s called; an arrow function takes the this from the place where it’s defined.
const obj = {
name: 'Curtis',
greetLater() {
setTimeout(function() {
console.log(this.name); // undefined (this isn't obj)
}, 100);
},
greetLaterArrow() {
setTimeout(() => {
console.log(this.name); // 'Curtis' (outer this preserved)
}, 100);
},
};Because of this difference — callbacks tend to be arrow functions, object methods tend to be regular functions or method shorthand. We cover this in depth in the Advanced series.
Which to use when? #
The most common practical guideline:
- Function declaration — meaningful module-top-level functions (
function calculate(...)) - Arrow function — short callbacks, transformations, computations (
map((x) => x * 2)) - Function expression — a relic from before arrow functions. Rarely used in new code
This series follows that guideline.
Parameters — default values #
Parameters can have default values.
function greet(name = 'anonymous') {
console.log(`hi, ${name}!`);
}
greet(); // hi, anonymous!
greet('Curtis'); // hi, Curtis!
greet(undefined); // hi, anonymous! ← undefined also triggers the default
greet(null); // hi, null! ← null is passed as-is
undefined triggers the default, but null is passed through. The two meanings of “no value yet” (#2) cause different behavior here.
Parameters — rest parameter (...rest)
#
When you don’t know how many arguments you’ll receive, gather them with ....
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2); // 3
sum(1, 2, 3, 4, 5); // 15
sum(); // 0
...numbers — gathers the remaining arguments into an array. Allowed only on the last parameter.
Combined with regular parameters #
function logCall(label, ...args) {
console.log(`[${label}]`, ...args);
}
logCall('debug', 1, 2, 3);
// [debug] 1 2 3
The ...args at the call site is called spread. Same ... syntax — different meaning depending on position. We revisit both in #5 Objects and Arrays.
Returning — return
#
The keyword that returns a value from a function.
function double(n) {
return n * 2;
}
double(5); // 10
When return runs, the function terminates immediately. Code after it doesn’t execute.
function describe(n) {
if (n === 0) return 'zero';
if (n < 0) return 'negative';
return 'positive';
}Early return reduces indentation and straightens the flow. Almost always more readable than deep if/else. A recommended pattern.
No return means undefined
#
function silent() {
console.log('done');
// no return
}
const result = silent();
console.log(result); // undefined
Every JavaScript function returns something. With no explicit return, undefined comes back automatically.
Hoisting — the special case of function declarations #
Before JavaScript runs your code, the engine lifts function declarations and variable declarations to the top — that’s hoisting.
Function declarations are hoisted completely, so you can call them anywhere.
console.log(add(2, 3)); // 5 — works even though we called it above the declaration
function add(a, b) {
return a + b;
}By contrast, function expressions and arrow functions are variables — using them before the declaration line errors.
console.log(add(2, 3)); // ✗ ReferenceError
const add = (a, b) => a + b;Most code declares before using, so you rarely think about hoisting. But the fact that only function declarations are hoisted up comes up when reading older code.
Closures — functions carry their environment #
Let’s preview one of JavaScript’s most powerful function characteristics.
function createCounter() {
let count = 0;
return function() {
count = count + 1;
return count;
};
}
const counter = createCounter();
counter(); // 1
counter(); // 2
counter(); // 3
Even though createCounter has finished, the inner count stays alive and is remembered by the returned function. A function that carries around the environment (scope) it was created in is called a closure.
Closures are one of JavaScript’s most important concepts and underlie the behavior of callbacks, event handlers, and hooks. We cover them in earnest in the Advanced series. For now, just hold on to “a function remembers its variables.”
Immediately Invoked Function Expression (IIFE) — old pattern #
A shape often seen in old code.
(function() {
console.log('runs as soon as it is created');
})();A pattern that calls the function as soon as it’s defined. In the days before modules, it was used as a trick to isolate variable scope. With modules today, it is rarely used. If you see one in old material, think “old-school module imitation.”
Wrap-up #
What we covered:
- Three ways to define a function — declaration / expression / arrow
- Arrow functions’ biggest difference:
thiscomes from the outside - Meaningful functions as declarations, short callbacks as arrows
- Default parameters —
undefinedtriggers the default;nullpasses through - Use
...restto gather variadic arguments - Early return straightens flow
- Only function declarations are hoisted — expressions follow variable rules
- Closures: a function remembers its environment
In the next post (#5 Objects and Arrays) we cover JavaScript’s two core data structures — basic usage of objects and arrays, plus modern syntax like spread/destructuring.