JavaScript has several ways to write a function. They mostly do the same thing, which is why seeing all of them in real code is confusing at first.
function add(a, b) { return a + b; } // declaration
const add2 = function (a, b) { return a + b; }; // expression
const add3 = (a, b) => a + b; // arrow functionAll three give you a working add. This guide explains when each is used.
Function declarations#
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet("Ada"));Declarations are hoisted, which means you can call them before the line where they are written. Good for top-level named functions.
Arrow functions#
const double = (n) => n * 2; // one expression, implicit return
const square = n => n * n; // single parameter, brackets optional
const greet = (name) => { // braces need an explicit return
const time = new Date().getHours();
return time < 12 ? `Morning, ${name}` : `Hello, ${name}`;
};The rule: no braces means the expression is returned automatically. Add braces and you must write return yourself. Forgetting that is a common source of functions that quietly return undefined.
Default and rest parameters#
function greet(name, greeting = "Hello") {
return `${greeting}, ${name}!`;
}
function total(...numbers) {
return numbers.reduce((sum, n) => sum + n, 0);
}
console.log(total(1, 2, 3)); // 6Callbacks: functions passed to other functions#
This is the pattern that makes JavaScript feel different from Python at first.
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8]
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
button.addEventListener("click", () => {
console.log("clicked");
});You are handing map a small function and letting it decide when to run it — once per item, in this case. See JavaScript arrays explained.
The other difference with arrow functions#
Arrow functions do not create their own this. Inside an object method that matters:
const counter = {
count: 0,
incrementBad: () => {
this.count++; // wrong — this is not the counter object
},
incrementGood() {
this.count++; // correct
},
};Practical rule: use arrow functions for callbacks and short helpers; use the method shorthand for functions that belong to an object.
Returning early#
function getDiscount(user) {
if (!user) return 0;
if (!user.isMember) return 0;
return user.yearsActive > 5 ? 20 : 10;
}Handling the awkward cases first keeps the main logic out of nested braces.
Questions people ask#
Which style should I use?
Arrow functions for callbacks and small helpers, named declarations for anything reusable and top-level. Consistency inside one project matters more than the choice itself.
What does a function return if there is no return statement?
undefined. This causes plenty of confusion when an arrow function with braces forgets its return.
What is an IIFE?
An immediately invoked function expression — (function () { ... })(); — which runs the moment it is defined. It was used to avoid polluting the global scope before modules existed. You will meet it in older code.
Can functions be stored in arrays and objects?
Yes. Functions are values in JavaScript, so you can store them, pass them around and return them from other functions.