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).
Return Values: undefined, Objects, and the ASI Trap
return sends a value back and immediately exits the function. A function with no return (or a bare return;) yields undefined. JavaScript adds one nasty gotcha here: automatic semicolon insertion.
function area(w, h) { return w * h; } // returns a value
function log(msg) { console.log(msg); } // returns undefined (no return)
// return multiple values via an object or array
function minMax(a) { return { min: Math.min(...a), max: Math.max(...a) }; }
const { min, max } = minMax([3, 1, 8]); // destructure the result
The newline-after-return trap
function bad() {
return // β JS inserts a semicolon HERE β returns undefined!
{ ok: true };
}
function good() {
return { ok: true }; // keep the value on the same line as return
}
Automatic Semicolon Insertion (ASI): JavaScript auto-inserts semicolons at line breaks β and if you put return on its own line with the value below, it "helpfully" ends the statement right after return, so the function returns undefined and the object below is dead code. Always keep the returned value on the same line as return (or open a bracket on that line). Multiple values: JS returns one value, so bundle several into an object (named fields) or array, then destructure at the call site. Consistency: a function that returns a value on some paths but falls through to undefined on others is a common bug β make sure every path returns, or none do.
ποΈ 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.
Related Topics
FAQ
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.

