JavaScript Functions Guide: Declarations, Expressions & Arrow Functions
Direct Answer & Key Concept
A JavaScript function is a reusable block of code designed to perform a specific task, accept arguments, and return computed results. JavaScript functions are first-class citizens, meaning they can be assigned to variables, passed as arguments, and returned from other functions.
// Comparing Function Declarations and Arrow Functions
function calculateTax(subtotal, rate = 0.08) {
return subtotal * rate;
}
const formatCurrency = amount => "$" + amount.toFixed(2);
const total = 100;
const tax = calculateTax(total);
console.log("Tax:", formatCurrency(tax)); // Tax: $8.00
console.log("Final Total:", formatCurrency(total + tax)); // Final Total: $108.00What is a function in JavaScript?
A JavaScript function is a fundamental building block of web applications that groups statements together into an invocable, reusable procedure. In JavaScript, functions are first-class citizens (first-class objects). This means functions can be stored in variables, passed into callbacks, returned from higher-order functions, and augmented with dynamic properties just like standard objects.
What are the types of functions in JavaScript?
Modern JavaScript provides multiple ways to declare and invoke functions, each serving distinct architectural patterns:
| Function Type | Syntax Example | Hoisted? | Own this Context? | Has arguments object? | Constructor (new)? |
| :--- | :--- | :--- | :--- | :--- | :--- |
| Function Declaration | function add(a, b) { return a + b; } | Yes (full body) | Yes (dynamic) | Yes | Yes |
| Function Expression | const add = function(a, b) { return a + b; }; | No (variable hoisted) | Yes (dynamic) | Yes | Yes |
| Arrow Function (ES6) | const add = (a, b) => a + b; | No | No (lexical this) | No (use rest ...args) | No |
When should you use Arrow Functions vs Traditional Functions?
Introduced in ECMAScript 2015 (ES6), arrow functions provide both a compact, concise syntax and fundamentally altered binding semantics:
1. Lexical this Binding
Traditional functions establish their this context dynamically based on how they are called at runtime. Arrow functions, by contrast, do not bind their own this; they lexically inherit this from the surrounding execution context. This makes arrow functions ideal for callbacks, timer functions (setTimeout), and array pipeline iterations (map, filter).
const timer = {
seconds: 0,
start() {
// Arrow function captures lexical 'this' from timer object
setInterval(() => {
this.seconds++;
}, 1000);
}
};
2. Implicit Return Syntax
When an arrow function contains only a single expression, the curly braces and return statement can be omitted:
const square = x => x * x;
const makeUser = (id, name) => ({ id, name }); // Note parens around object literal
When NOT to use arrow functions:
- Object methods: If you need
thisto point to the host object, use standard shorthand method syntax (greet() { return this.name; }). - Constructors: Arrow functions cannot be called with the
newkeyword and do not possess a.prototypeproperty. - Event handlers requiring
thiselement: DOM event callbacks that inspectthisas the clicked DOM element should use regular function declarations.
What are Default Parameters and Rest Parameters?
Modern JavaScript simplifies function signatures by eliminating defensive parameter boilerplate:
Default Parameters
Default parameters allow initializing formal parameters with default values if no value or undefined is passed:
function paginate(page = 1, pageSize = 20) {
return { offset: (page - 1) * pageSize, limit: pageSize };
}
Rest Parameters (...rest)
Rest parameters condense an indefinite number of arguments into a real array, replacing the outdated array-like arguments object:
function calculateTotal(discount, ...prices) {
const sum = prices.reduce((acc, price) => acc + price, 0);
return sum * (1 - discount);
}
Common Mistakes with JavaScript Functions
- Returning object literals without parentheses in arrow functions: Writing
() => { a: 1 }interprets the braces as a function body block rather than an object literal. Wrap in parentheses:() => ({ a: 1 }). - Calling arrow functions with new: Calling
new MyArrowFunc()throws a runtimeTypeError: MyArrowFunc is not a constructor. - Assuming function arguments can be sliced directly: The legacy
argumentsobject is an array-like structure without array prototype methods. Use modern rest parameters...argsinstead.