Functions in JavaScript – Notes (The Thing That Makes Code Actually Reusable)
Okay so we've covered a lot of ground. Variables, data types, operators, control flow, objects, classes, arrays. And honestly functions have been quietly showing up in almost everything we've done – we wrote methods inside classes, we used console.log which is itself a function, we've been calling things with parentheses without really stopping to ask why. Today we actually sit down and properly understand what functions are, how to write them two different ways, and one slightly mind-bending thing called hoisting that caught me completely off guard when I first saw it.
What Is a Function and Why Do We Need One?
Let me start with a real situation. Say you're writing a program and at five different points in the code you need to calculate the area of a rectangle. Without functions you'd write the same calculation five times in five different places. Now your boss says hey the formula changed. You now have to go find all five places and change them one by one. Miss even one and your program gives wrong answers and you don't even know why.
Functions fix this completely. A function is a reusable block of code that you write once, give a name, and then call as many times as you need from anywhere in your program. If something needs to change you change it in one place. Done.
Beyond avoiding repetition, functions also make your code dramatically easier to read. Instead of seeing 15 lines of calculation logic dumped in the middle of your program, you see one line that says calculateArea() and you immediately understand what it does. The details are tucked away neatly inside the function definition.
So – reusability and readability. Those are the two big reasons functions exist and they're both genuinely important.
Function Declaration – The Classic Way
The first way to write a function is called a function declaration. Here's the syntax:
function greet() {
console.log("Hello! Welcome.");
}
You start with the function keyword, then the name you're giving it, then parentheses, then curly braces containing the code to run. To actually run the function you call it by writing its name followed by parentheses:
greet(); // Hello! Welcome.
Functions get really useful when you pass information into them. You do this using parameters – placeholders in the parentheses that receive values when the function is called:
function greet(name) {
console.log("Hello, " + name + "! Welcome.");
}
greet("Aryan"); // Hello, Aryan! Welcome.
greet("Priya"); // Hello, Priya! Welcome.
greet("Rohan"); // Hello, Rohan! Welcome.
Same function, different output each time based on what you pass in. The values you pass in when calling the function are called arguments. So name is the parameter, "Aryan" is the argument. Teachers love asking that distinction in exams.
Most functions also give something back using the return keyword:
function addNumbers(a, b) {
return a + b;
}
let result = addNumbers(10, 5);
console.log(result); // 15
return sends a value back out of the function to wherever it was called from. Once the function hits a return statement it stops running immediately and hands back that value. If there's no return statement the function just runs its code and gives back undefined.
Function Expression – The Second Way
A function expression is when you create a function and store it in a variable. Like this:
let addNumbers = function(a, b) {
return a + b;
};
let result = addNumbers(10, 5);
console.log(result); // 15
Notice the differences. There's no function name after the function keyword – this is called an anonymous function because the function itself has no name, the variable is what holds it. And there's a semicolon at the end because this is a variable assignment statement, same as let x = 5;
You call it exactly the same way as a declaration though – just the variable name followed by parentheses. The behaviour of the function itself is identical. It takes parameters, does stuff, returns a value. All the same rules apply.
So functionally these two produce the same result:
// Declaration
function multiply(a, b) {
return a * b;
}
// Expression
let multiply = function(a, b) {
return a * b;
};
console.log(multiply(4, 5)); // 20 either way
Same output. So why does the second way even exist? Great question. This is where hoisting comes in.
Hoisting – The Part That Surprised Me
Okay this is the thing that made me do a double take when I first saw it. Try this with a function declaration:
console.log(sayHello()); // Hello!
function sayHello() {
return "Hello!";
}
Wait. We called the function BEFORE we defined it. And it worked. How?
This is hoisting. JavaScript, before it actually runs your code, does a quick scan of the entire file and moves certain things to the top in memory. Function declarations get hoisted – meaning JavaScript knows about them before it starts running your code line by line. So even though you wrote the call before the definition, JavaScript had already registered the function.
Now try the same thing with a function expression:
console.log(sayHello()); // ERROR – sayHello is not a function
let sayHello = function() {
return "Hello!";
};
This crashes. Because sayHello is a variable, and variables aren't hoisted the same way. At the time you try to call sayHello it hasn't been assigned yet. JavaScript knows the variable exists (because let declarations are hoisted in a limited way) but it doesn't have the function stored in it yet. So calling it throws an error.
I want to be clear this is a simplified explanation. The full story of how JavaScript hoisting works is a whole rabbit hole involving something called the execution context and temporal dead zones and honestly that's a lot more than we need right now. The practical takeaway is just this:
Function declarations can be called before they appear in the code. Function expressions cannot.
That's the version that matters day to day.
When to Use Each One
This is the question I had after learning both. If they do the same thing, when do I choose which one?
Use a function declaration when you're writing a general purpose reusable function that might be called from multiple places. Things like calculateTax(), getUserDetails(), validateForm(). The kind of function that's a named utility doing a clearly defined job. Declarations are easier to read, they have a proper name that shows up in error messages which helps with debugging, and hoisting means you can organise your file however feels natural without worrying about call order.
Use a function expression when you're assigning a function to something – like storing it in a variable to pass it around, or when you're writing a function that's only used once in a specific spot. Function expressions are also the foundation for something called arrow functions which is a shorter cleaner syntax you'll learn soon. Most modern JavaScript code uses expressions a lot for this reason.
Honestly for where we are right now the difference is minor. Get comfortable with both. As you write more code you'll naturally start to feel when each one fits.
Side by Side Comparison
Just to have it clearly laid out:
Function Declaration:
function square(n) {
return n * n;
}
console.log(square(5)); // 25
Function Expression:
let square = function(n) {
return n * n;
};
console.log(square(5)); // 25
Declaration – starts with the function keyword, has a name, no semicolon at the end, gets hoisted. Expression – stored in a variable, function keyword comes after the equals sign, semicolon at the end, does NOT get hoisted.
Assignment
Task 1 – Function Declaration That Multiplies Two Numbers
function multiply(a, b) {
return a * b;
}
let result1 = multiply(6, 7);
console.log("Declaration result: " + result1); // 42
Task 2 – Same Logic as a Function Expression
let multiply = function(a, b) {
return a * b;
};
let result2 = multiply(6, 7);
console.log("Expression result: " + result2); // 42
Both produce 42. Same logic, different syntax.
Task 3 – Call Before Defining and See What Happens
// Trying with declaration first
console.log(multiplyDec(4, 5)); // 20 – works because of hoisting
function multiplyDec(a, b) {
return a * b;
}
// Now trying with expression
console.log(multiplyExp(4, 5)); // TypeError: multiplyExp is not a function
let multiplyExp = function(a, b) {
return a * b;
};
The declaration call before the definition works perfectly. The expression call before the definition throws a TypeError. Exactly what the hoisting explanation predicted. I actually tested both of these in my browser console and saw it happen live which made it stick way better than just reading about it.
Quick Recap
A function is a reusable named block of code that runs when called
Parameters are the placeholders in the definition, arguments are the actual values passed when calling
return sends a value back out of the function
Function declarations use the function keyword followed by a name – they get hoisted so they can be called before they appear in the file
Function expressions store a function in a variable – they do NOT get hoisted so they must be defined before being called
Use declarations for general reusable utilities, use expressions when assigning functions to variables or for more specific scoped uses
Hoisting is JavaScript moving certain things to the top of memory before running code – simplified version for now, full story comes later
Functions are honestly one of those things where the more you use them the more you appreciate them. Every piece of code you'll ever write for the rest of your life as a programmer will involve functions. Getting the fundamentals solid here really does matter.