If you are new to JavaScript—or even if you’ve been writing it for years—you’ve likely noticed that there isn't just one way to write a function. Unlike many other languages that have a single, strict syntax for subroutines, JavaScript offers a buffet of options.
From the classic Declaration to the modern Arrow Function, each method behaves slightly differently regarding hoisting, the this keyword, and readability.
In this guide, we’ll break down the most common ways to write functions in JavaScript and when you should use which.
1. The Classic: Function Declaration
This is the most traditional way to define a function. It starts with the function keyword, followed by the name of the function.
function sayHello(name) {
return `Hello, ${name}!`;
}
console.log(sayHello("Alice")); // Output: Hello, Alice!
The Superpower: Hoisting
The defining feature of a Function Declaration is hoisting. You can call the function before you define it in your code. The JavaScript engine moves these definitions to the top of the scope before execution.
// This works perfectly!
greet();
function greet() {
console.log("I have been hoisted!");
}
✅ When to use it: When you want to define global utilities or prefer reading your code with the high-level logic at the top and the function details at the bottom.
2. The Variable approach: Function Expression
A Function Expression involves creating a function (usually anonymous) and assigning it to a variable (var, let, or const).
const add = function(a, b) {
return a + b;
};
console.log(add(5, 3)); // Output: 8
The Difference
Unlike declarations, Function Expressions are not hoisted. You cannot call them before the line where they are defined.
✅ When to use it: When you need to pass a function as an argument to another function, or when you want to enforce a strict top-to-bottom code execution flow.
3. The Modern Standard: Arrow Functions (ES6)
Introduced in ES6 (2015), Arrow Functions completely changed how we write JavaScript. They offer a concise syntax and are often used for one-liners.
// Multiline syntax
const multiply = (a, b) => {
return a * b;
};
// Implicit return (one-liner)
const square = x => x * x;
The "this" Trap
Arrow functions do not have their own this binding. They inherit this from the parent scope (lexical scoping). This makes them perfect for callbacks inside classes but terrible for object methods where you need dynamic context.
✅ When to use it: Array methods (like .map, .filter), simple utilities, and preserving context in React components.
4. The Object Method Shorthand
When defining functions inside an object, you don't need the generic function keyword anymore. You can use the shorthand syntax.
const user = {
name: "Jordan",
// Old way
login: function() {
console.log("Logged in");
},
// Modern Shorthand
logout() {
console.log("Logged out");
}
};
✅ When to use it: Always, when defining methods inside object literals. It’s cleaner and easier to read.
5. Immediately Invoked Function Expressions (IIFE)
Sometimes you want a function to run as soon as it is defined, usually to create a private scope and avoid polluting the global namespace.
(function() {
const secret = "I am hidden";
console.log("I run immediately!");
})();
// console.log(secret); // ReferenceError
✅ When to use it: Module patterns or initialization code that only needs to run once. (Note: Modern ES Modules have largely replaced the need for this, but you will still see it in older codebases).
Summary: Which one should I choose?
Here is a quick reference table to help you decide:
| Type | Syntax | Hoisted? | Handles this? | Best For |
| Declaration | function x() {} | Yes | Dynamic | Main helpers, Global scope |
| Expression | const x = function() {} | No | Dynamic | Passing as arguments |
| Arrow | const x = () => {} | No | Lexical (inherited) | One-liners, Callbacks |
| Method | obj = { x() {} } | No | Dynamic | Object methods |
Final Thought
There is no "wrong" way to write a function, but consistency is key. Modern teams often default to Arrow Functions for almost everything due to their brevity, reverting to Function Declarations only when hoisting is specifically needed.

0 Comments