The return Statement
The return statement ends function execution and specifies the value the function produces. Execution resumes in the calling code at the point where the function was called.
function add(a, b) {
return a + b; // Function ends here; value is sent back
console.log("This never runs"); // Dead code after return
}
const result = add(5, 3);
console.log(result); // 8
// The returned value can be used anywhere
console.log(add(10, 20) * 2); // 60
const greeting = "Sum is: " + add(1, 2);
console.log(greeting); // Sum is: 3
Implicit undefined Return
A function with no return statement β or a bare return; β implicitly returns undefined.
// No return statement
function logMessage(msg) {
console.log(msg);
// Implicitly returns undefined
}
const x = logMessage("Hello"); // Hello
console.log(x); // undefined
// Bare return (used to exit early from a void function)
function printIfPositive(n) {
if (n <= 0) return; // Exit immediately
console.log("Positive: " + n);
}
printIfPositive(-1); // Prints nothing
printIfPositive(5); // Positive: 5
Never put a newline immediately after return. JavaScript inserts a semicolon after return at the end of the line, making the function return undefined. Always keep the returned value on the same line, or use parentheses.
// Bug: returns undefined!
return
{ value: 42 };
// Correct:
return { value: 42 };
// Or:
return (
{ value: 42 }
);
Returning Multiple Values
JavaScript can only return one value per return. Bundle multiple values in an array or object, then destructure at the call site.
// Return as array
function minMax(numbers) {
const sorted = [...numbers].sort((a, b) => a - b);
return [sorted[0], sorted[sorted.length - 1]];
}
const [min, max] = minMax([3, 1, 8, 2, 9, 4]);
console.log(`Min: ${min}, Max: ${max}`); // Min: 1, Max: 9
// Return as object β named, easier to read
function getStats(numbers) {
const sum = numbers.reduce((a, b) => a + b, 0);
return {
count: numbers.length,
sum,
average: sum / numbers.length,
min: Math.min(...numbers),
max: Math.max(...numbers)
};
}
const stats = getStats([5, 10, 15, 20]);
console.log(stats);
const { average, count } = getStats([2, 4, 6]);
console.log(`Average of ${count} items: ${average}`);
Early Return Pattern
Return as soon as you know the answer, without executing unnecessary code.
// Without early return β deeply nested
function getDiscount(user, cart) {
let discount = 0;
if (user) {
if (cart.total > 0) {
if (user.isPremium) {
if (cart.total >= 100) {
discount = 0.20;
} else {
discount = 0.10;
}
}
}
}
return discount;
}
// With early return β flat and clear
function getDiscountClean(user, cart) {
if (!user) return 0;
if (cart.total <= 0) return 0;
if (!user.isPremium) return 0;
return cart.total >= 100 ? 0.20 : 0.10;
}
const user = { isPremium: true };
console.log(getDiscountClean(user, { total: 150 })); // 0.2
console.log(getDiscountClean(null, { total: 150 })); // 0
Functions as Return Values
Because functions are first-class values, a function can return another function. This is the foundation of closures, factory functions, and currying.
// Factory function β returns a configured function
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
const tenX = createMultiplier(10);
console.log(double(5)); // 10
console.log(triple(5)); // 15
console.log(tenX(5)); // 50
// Practical: greeting factory
function createGreeter(greeting) {
return (name) => `${greeting}, ${name}!`;
}
const sayHello = createGreeter("Hello");
const sayHowdy = createGreeter("Howdy");
console.log(sayHello("Alice")); // Hello, Alice!
console.log(sayHowdy("Bob")); // Howdy, Bob!
Chaining with Return Values
// Method chaining (builder pattern)
class QueryBuilder {
constructor() { this.query = {}; }
where(field, value) {
this.query[field] = value;
return this; // Return 'this' enables chaining
}
limit(n) {
this.query._limit = n;
return this;
}
build() {
return this.query;
}
}
const q = new QueryBuilder()
.where("status", "active")
.where("role", "admin")
.limit(10)
.build();
console.log(q);
Pure Functions
A pure function: (1) given the same inputs, always returns the same output; (2) has no side effects (doesn't modify external state, I/O, etc.).
// Pure function β same input always β same output, no side effects
function calculateTax(price, taxRate) {
return price * (1 + taxRate);
}
console.log(calculateTax(100, 0.1)); // 110 (always)
console.log(calculateTax(100, 0.1)); // 110 (same input β same output)
// Impure function β depends on external state
let taxRate = 0.1;
function calculateTaxImpure(price) {
return price * (1 + taxRate); // Depends on external taxRate
}
taxRate = 0.2;
console.log(calculateTaxImpure(100)); // 120 (result changed!)
Pure functions are easier to test, debug, and reason about. You can always trust a pure function's output given its inputs. Aim for pure functions as the default; use impure functions only when side effects are necessary (DOM updates, API calls, logging).
ποΈ Practical Exercise
Write a pure function processOrder(order) that takes an order object with items (array of { name, price, qty }) and discountCode. It should return an object with:
subtotalβ sum of price Γ qty for all itemsdiscountβ 10% if discountCode is "SAVE10", else 0totalβ subtotal minus discountitemCountβ total quantity of all items
π₯ Challenge Exercise
Build a curry(fn) function that transforms any function into a curried version. A curried function returns partial functions until all arguments are collected, then executes. Example: curry((a, b, c) => a + b + c)(1)(2)(3) should return 6. Also support calling with multiple args at once: curry(fn)(1, 2)(3).
π Summary
return value;ends a function and sends the value to the caller.- No return or bare
return;β function returnsundefined. - Return multiple values by wrapping in an array or object, then destructuring.
- Early return replaces deeply nested if/else with flat, readable logic.
- Functions can return other functions β enabling factory functions and currying.
- Pure functions (same input β same output, no side effects) are easy to test and trust.
Interview Questions
- What does a function return if it has no return statement?
- How do you return multiple values from a JavaScript function?
- What is the automatic semicolon insertion trap with return?
- What is a pure function? Why are pure functions preferred?
- Explain the factory function pattern with a code example.
Frequently Asked Questions
Yes. Only one return executes per call β once one is hit, the function ends. Multiple returns are the basis of the early return / guard clause pattern.
Yes, and this is used heavily in functional programming (currying, partial application). Each returned function closes over the variables from its outer scope, forming a closure chain.
return produces a value that the caller can use. console.log is a side effect that prints to the console but returns undefined. A function that only logs cannot be composed with other functions.