A function in JavaScript is a named, reusable piece of behaviour: you give it arguments, it gives you a value back. There are several ways to declare one, and they differ in ways that matter — whether the name exists before the line runs, whether it can be called with new, and what this means inside it.
How do I declare a function?
Two forms cover almost everything you will write. A function declaration names the function and puts it in scope for the whole enclosing block. A function expression creates an unnamed function and assigns it to a variable.
// Declaration: the name is hoisted.
function greet(name) {
return `Hello, ${name}!`;
}
// Expression: the function has no name of its own.
const farewell = function (name) {
return `Goodbye, ${name}!`;
};
console.log(greet("Ada")); // "Hello, Ada!"
console.log(farewell("Ada")); // "Goodbye, Ada!"
The difference in naming is not cosmetic. A declaration has a name the engine knows about, so it shows up in stack traces and in the debugger's call stack, and you can call it before the line where it is written. A function expression only has the name of the variable it is assigned to — and even that is not visible inside the function body, which matters when you want to call a function recursively.
Arrow functions are the third form and the one you will use most often. They are covered in their own lesson later in this module, because the differences from a regular function are about behaviour rather than syntax alone.
Why can I call a function before I define it?
Because function declarations are hoisted. The engine registers the name and the function before it runs a single statement of your file, so the call works even though the definition appears further down.
console.log("before:", greet("Ada")); // works fine
function greet(name) {
return `Hello, ${name}!`;
}
// A function expression does not get the same treatment:
const farewell = function (name) {
return `Goodbye, ${name}!`;
};
console.log(typeof farewell); // "function"
Hoisting applies to function declarations only. A function stored in a const is a binding that has not been initialised yet at that point in the file, so calling it earlier throws a ReferenceError — the same temporal dead zone you met with let and const. The last line prints "function" because by that point the assignment has run.
This is not a licence to write code out of order. Most style guides put declarations before use anyway, because a reader coming to a file top-to-bottom should not have to know that hoisting exists.
How do you call a function?
With parentheses. The name goes first, then the arguments in brackets.
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
console.log(add(10, 5)); // 15
console.log(add("Total: ", 5)); // "Total: 5"
Notice that the function does not care what the arguments are. It adds them, and JavaScript's own rules for + decide what that means — which is why add("Total: ", 5) produces a string. A function that behaves differently for numbers and strings without being asked to is usually a sign it needs a clearer contract, and the parameters and return values lesson later in this module covers how to design one.
You can also call a function without using its result, and you can assign the result to a variable, and both are completely normal.
Can a function be a value?
Yes, and this is the idea that makes JavaScript functions genuinely different from methods in older languages. A function is an object, so it can be stored in a variable, put in an array, passed to another function, or returned from one.
const operations = {
add: (a, b) => a + b,
multiply: (a, b) => a * b,
};
function run(operation, a, b) {
return operation(a, b);
}
console.log(run(operations.add, 2, 3)); // 5
console.log(run(operations.multiply, 2, 3)); // 6
const double = (n) => n * 2;
const doubled = [1, 2, 3].map(double);
console.log(doubled); // [ 2, 4, 6 ]
The last two lines show the payoff. run does not know what it is being given — it just calls whatever function arrives. That is why callbacks work, why array methods like map exist, and why event handlers can be swapped at runtime.
One consequence worth knowing: a function declaration is also a value, so it can be reassigned like any other variable.
What is an immediately invoked function expression?
A function expression wrapped in parentheses and called straight away. It runs once and then disappears, and its internal variables stay out of the surrounding scope.
const result = (function () {
const secret = "hidden inside";
return secret.toUpperCase();
})();
console.log(result); // "HIDDEN INSIDE"
console.log(typeof secret); // "undefined"
Before ES modules existed, this was the standard way to keep a file's variables from leaking into the global scope, and it still appears in plenty of older code. In modern JavaScript you do not usually need it: a const at the top level of a module is already scoped to that module.
The arrow-function equivalent is shorter, and is the form you will see in most current code:
const result = (() => {
const secret = "hidden inside";
return secret.toUpperCase();
})();
console.log(result); // "HIDDEN INSIDE"
What happens when a function is a property of an object?
It is called a method, and the object it belongs to is available inside the function as this. That is the only difference between a function and a method — the same function value, called in a different way.
const cart = {
items: ["book", "pen"],
count() {
return this.items.length;
},
};
console.log(cart.count()); // 2
const standalone = cart.count;
console.log(typeof standalone); // "function"
Call it as cart.count() and this is the cart, so it returns 2. Pull the same function out into standalone and this is no longer the cart — calling it that way usually throws, because there is no object for this to point at.
This is worth understanding now even though arrow functions and this get their own lesson later, because it explains something you have probably already seen: const standalone = cart.count followed by standalone() breaks in a way that looks mysterious. It is not mysterious. The function was never attached to the object; only the call was.
The function rules worth remembering
- A declaration is hoisted and can be called before it is written. A function expression stored in
constcannot. - Give function expressions a name when you will need to call them recursively.
- Functions are values: store them, pass them, return them.
- A method is just a function called as a property of an object, which is what makes
thisavailable inside it. - An immediately invoked function expression runs once and keeps its variables private. ES modules make it unnecessary in new code.
Try it yourself: write a function formatOrder(order) that returns a summary string, then write the same logic three ways — as a declaration, as a function expression, and as an arrow function. Pass each one to a helper that calls it with a sample order. Then convert one of them into a method on an order object and call it both as order.formatOrder() and as a detached function, and note exactly where the second version stops working.