JavaScript Return Statement Get Certified
The return statement is how a function sends a value
back to the code that called it. It’s one of the most important
tools for making functions genuinely reusable, rather than just
blocks of code that print things to the console.
In this lesson, you will learn how return works, how
early returns (guard clauses) simplify code, the difference between
return and console.log, and how to return
multiple values.
Basic return Usage
A return statement sends a value back to wherever
the function was called, so it can be stored, logged, or used in
further calculations.
What this code does: return sends a value back to the caller and exits the function.
circleArea(5) computes the area and returns it; that value is stored in area and printed.
function circleArea(radius) {
return Math.PI * radius * radius;
}
let area = circleArea(5);
console.log(area);
function circleArea(radius) { declares a function with one parameter, radius.return Math.PI * radius * radius; calculates the area of a circle (π × radius²) and sends the value back to the code that called the function. Math.PI is JavaScript’s built-in value of π (about 3.14159). The return also ends the function.} ends the function body.let area = circleArea(5); calls the function with a radius of 5. The function returns the area, and that value is stored in the variable area. Nothing is printed by this line.console.log(area); prints the value that was returned: 78.53981633974483 (π × 5 × 5). Because the value was returned, it can also be reused in further calculations, not just printed.return Immediately Exits the Function
As soon as a return statement runs, the function
stops executing. Any code written after it in the same block is
never reached.
What this code does: As soon as return runs, the function stops.
The console.log after the return never executes. The function returns true or false.
function checkStock(quantity) {
return quantity > 0;
console.log("This line never runs.");
}
console.log(checkStock(5));
console.log(checkStock(0));
function checkStock(quantity) { declares a function with one parameter, quantity.return quantity > 0; first evaluates the comparison quantity > 0, which gives true or false, and then returns that result. As soon as return runs, the function stops.console.log("This line never runs."); comes after the return, so it is never reached. JavaScript allows this, but it is a mistake, because code after a return is dead code.} ends the function body.checkStock(5) evaluates 5 > 0, which is true, and returns it. The output is true.checkStock(0) evaluates 0 > 0, which is false. The output is false. The message on line 3 is never printed in either call.Early Returns (Guard Clauses)
A common pattern is to return early when a certain
condition is met, avoiding deeply nested if...else
blocks. This is often called a guard clause.
What this code does: Multiple early returns act as guard clauses—each condition returns a different label. Membership years of 0, 3, and 7 produce different discount messages.
function getDiscountLabel(membershipYears) {
if (membershipYears < 1) {
return "No discount";
}
if (membershipYears < 5) {
return "5% loyalty discount";
}
return "10% loyalty discount";
}
console.log(getDiscountLabel(0));
console.log(getDiscountLabel(3));
console.log(getDiscountLabel(7));
function getDiscountLabel(membershipYears) { declares a function with one parameter: how many years the customer has been a member.if (membershipYears < 1) { checks for members of less than one year. A check like this, which handles a special case and leaves the function early, is called a guard clause.return "No discount"; runs only for new members. It returns the label and ends the function immediately, so none of the code below is executed for them.} closes the first if block.if (membershipYears < 5) { is only reached by members of 1 year or more (the first guard already handled the rest). So this condition effectively means 1 to 4 years.return "5% loyalty discount"; returns the middle tier and ends the function.} closes the second if block.return "10% loyalty discount"; is only reached by members of 5 years or more, since earlier returns handled everything else. No else is needed.} ends the function body.getDiscountLabel(0) matches the first guard, so the output is No discount.getDiscountLabel(3) skips the first guard (3 is not below 1) and matches the second, so the output is 5% loyalty discount.getDiscountLabel(7) skips both guards and reaches the final return, so the output is 10% loyalty discount.
Each condition returns immediately once it matches, so there’s no
need for else blocks at all.
Using return for Input Validation
Guard clauses are especially useful for exiting a function early when the input is invalid, before running the rest of the logic.
What this code does: Guard clauses check for invalid input first and return an error message. Only valid inputs reach the BMI calculation. Invalid height returns a message instead of a number.
function calculateBmi(weightKg, heightM) {
if (heightM <= 0) {
return "Invalid height";
}
if (weightKg <= 0) {
return "Invalid weight";
}
return (weightKg / (heightM * heightM)).toFixed(1);
}
console.log(calculateBmi(70, 1.75));
console.log(calculateBmi(70, 0));
function calculateBmi(weightKg, heightM) { declares a function with two parameters: weight in kilograms and height in metres.if (heightM <= 0) { checks whether the height is zero or negative, which makes no sense for a person and would cause a division by zero.return "Invalid height"; exits the function right away with an error message, before any calculation is attempted.} closes the first if block.if (weightKg <= 0) { checks for an impossible weight in the same way.return "Invalid weight"; exits with a different error message.} closes the second if block.return (weightKg / (heightM * heightM)).toFixed(1); is reached only with valid input. BMI is weight divided by height squared. .toFixed(1) rounds the result to one decimal place and returns it as text. For 70 kg and 1.75 m this is 70 / 3.0625, which rounds to 22.9.} ends the function body.calculateBmi(70, 1.75) passes both guards and returns the calculated value. The output is 22.9.calculateBmi(70, 0) triggers the first guard, so the function returns early. The output is Invalid height.return Without a Value
return can be used on its own, with no value, simply
to exit the function early. In this case, the function returns
undefined.
What this code does: A bare return; exits early and returns undefined.
Negative numbers are ignored; only positive numbers are logged.
function logIfPositive(number) {
if (number <= 0) {
return;
}
console.log(number, "is positive.");
}
logIfPositive(5);
logIfPositive(-2);
function logIfPositive(number) { declares a function with one parameter, number. Its job is to print a message, not to return a value.if (number <= 0) { checks whether the number is zero or negative.return; has no value after it. It simply ends the function early. The function returns undefined, and nothing is printed for this input.} closes the if block.console.log(number, "is positive."); is only reached when the guard did not return, so only for positive numbers. It prints the number followed by the text.} ends the function body.logIfPositive(5); passes the guard and prints 5 is positive.logIfPositive(-2); hits the bare return; and prints nothing. The only output of the example is 5 is positive.Functions Without a return Statement
If a function never reaches a return statement at
all, it implicitly returns undefined once it
finishes running.
What this code does: A function with no return always returns undefined.
printReceipt only logs; storing its result in output gives undefined.
function printReceipt(itemName, price) {
console.log(itemName + ": $" + price);
}
let output = printReceipt("Coffee", 4.5);
console.log(output);
function printReceipt(itemName, price) { declares a function with two parameters.console.log(itemName + ": $" + price); joins the item name, a colon and a dollar sign, and the price into one line, and prints it. The function has no return statement.} ends the function body. Because the function reaches its end without a return, it automatically returns undefined.let output = printReceipt("Coffee", 4.5); calls the function. While it runs, it prints Coffee: $4.5. Then it returns undefined, which is stored in output.console.log(output); prints undefined. The complete output is Coffee: $4.5 and then undefined.return vs. console.log
A common source of confusion for beginners is mixing up
return and console.log.
console.log only displays a value in the console; it
doesn’t hand that value back to the rest of the program.
What this code does: console.log is for display; return is for giving a value to the caller.
The log version’s result is undefined; the return version’s result is 10 and can be reused.
function doubleWithLog(number) {
console.log(number * 2);
}
function doubleWithReturn(number) {
return number * 2;
}
let loggedResult = doubleWithLog(5);
let returnedResult = doubleWithReturn(5);
console.log("From console.log version:", loggedResult);
console.log("From return version:", returnedResult);
function doubleWithLog(number) { declares the first version. It will only display its answer.console.log(number * 2); prints the doubled value to the console. It does not hand the value back to the caller.} ends the first function. It returns undefined, since it has no return.function doubleWithReturn(number) { declares the second version. It will give back its answer.return number * 2; sends the doubled value back to the caller, so the caller can store it or use it.} ends the second function.let loggedResult = doubleWithLog(5); calls the first function. Inside, line 2 prints 10 straight away, which is the first line of output. Then the function returns undefined, which is stored in loggedResult.let returnedResult = doubleWithReturn(5); calls the second function, which prints nothing. It returns 10, which is stored in returnedResult.From console.log version: undefined. The value was displayed earlier, but it was never given back, so there is nothing to use.From return version: 10. This value can be stored, used in calculations or passed to other functions. The complete output is 10, From console.log version: undefined and From return version: 10.
Only doubleWithReturn actually gives us a usable
value; doubleWithLog just prints its result and
returns undefined.
Returning Multiple Values
A function can only return one value directly, but that value can be an array or an object containing multiple pieces of data.
What this code does: To return several related values, return an object (or array).
getMinMax returns both min and max in one object, which are then printed.
function getMinMax(numbers) {
return {
min: Math.min(...numbers),
max: Math.max(...numbers)
};
}
const result = getMinMax([12, 5, 30, 8, 19]);
console.log(result.min, result.max);
function getMinMax(numbers) { declares a function with one parameter, which will be an array of numbers.return { starts returning an object. A function can return only one value, but that value can be an object holding several related values. The opening brace is on the same line as return, which is important (see the last pitfall on this page).min: Math.min(...numbers), creates a property named min. The three dots ... (the spread operator) spread the array into separate arguments, because Math.min() expects separate numbers, not an array. The smallest is 5.max: Math.max(...numbers) creates the property max in the same way. The largest is 30.}; closes the object and ends the return statement.} ends the function body.const result = getMinMax([12, 5, 30, 8, 19]); passes an array of five numbers. The function returns an object, which is stored in result.console.log(result.min, result.max); reads the two properties with dot notation and prints them on one line: 5 30.You can also return an array and destructure it directly at the call site.
What this code does: Returning an array lets the caller use destructuring to unpack the values. The full name is split into first and last name, which are printed separately.
function splitFullName(fullName) {
return fullName.split(" ");
}
const [firstName, lastName] = splitFullName("Michael Johnson");
console.log(firstName);
console.log(lastName);
function splitFullName(fullName) { declares a function with one parameter, a full name as text.return fullName.split(" "); uses the string method split(), which cuts the text at every space and returns the pieces as an array. For "Michael Johnson" that is ["Michael", "Johnson"].} ends the function body.const [firstName, lastName] = splitFullName("Michael Johnson"); calls the function, and unpacks the returned array straight into two variables, by position: the first item goes into firstName and the second into lastName.console.log(firstName); prints Michael.console.log(lastName); prints Johnson.return Inside a Loop
When return is used inside a loop within a function,
it exits the entire function immediately, not just the loop. This
is useful for stopping a search as soon as a match is found.
What this code does: Early return inside a loop stops searching as soon as a match is found.
If no user matches the id, the function returns null after the loop.
function findUserById(users, id) {
for (let i = 0; i < users.length; i++) {
if (users[i].id === id) {
return users[i];
}
}
return null;
}
const users = [
{ id: 1, name: "Sofia" },
{ id: 2, name: "James" },
{ id: 3, name: "Lena" }
];
console.log(findUserById(users, 2));
console.log(findUserById(users, 99));
function findUserById(users, id) { declares a function with two parameters: the array of users to search, and the id to look for.for (let i = 0; i < users.length; i++) { visits each index of the array, from 0 up to the last user.if (users[i].id === id) { checks whether the id of the current user matches the one we are searching for.return users[i]; returns the matching user. Because it is inside the loop, it exits the entire function at once, not just the loop. The remaining users are never checked.} closes the if block.} closes the for loop. The loop only gets to its natural end if no user matched.return null; runs only if the loop finished without finding a match. null is the usual way to say no result.} ends the function body.const users = [ starts an array of user objects.{ id: 1, name: "Sofia" }, is a user object with an id and a name.{ id: 2, name: "James" }, is the second user. This is the one that the first search will find.{ id: 3, name: "Lena" } is the last user, so there is no comma after it.]; closes the array and ends the statement.findUserById(users, 2): the loop checks id 1 (no) and then id 2 (yes), and returns James’s object at once. The output is the object with id 2 and name "James".findUserById(users, 99) checks all three users without a match, then reaches return null;. The output is null.
As soon as a matching user is found, return exits
the function entirely — the loop never checks the remaining
users.
Watch Out for Automatic Semicolon Insertion
Placing a newline directly after return and before
the value can cause unexpected behavior, because JavaScript may
automatically insert a semicolon right after
return.
What this code does: A newline after return triggers automatic semicolon insertion,
so the function returns undefined and the object is never returned. Keep the value on the same line as return.
function getUserObject() {
return
{
name: "Michael"
};
}
console.log(getUserObject());
function getUserObject() { declares a function with no parameters. The intention is for it to return an object.return is on a line by itself, with the value on the following lines. JavaScript has a rule called automatic semicolon insertion: it sees the line break right after return and treats the code as return;. The function ends here and returns undefined.{ starts what looks like an object, but because of the inserted semicolon it is parsed as a separate block of code that is never executed.name: "Michael" is never used. Here it is read as a label followed by a text, not as an object property.}; closes that unreachable block.} ends the function body.console.log(getUserObject()); prints undefined, not the object. The fix is to keep the opening brace on the same line as return: return {.
Because of automatic semicolon insertion, this function actually
returns undefined — the object literal on the next
line is never reached. Always keep the returned value on the same
line as return.
Practical Example
Let’s use return with guard clauses to validate a
password before accepting it.
What this code does: A practical validation function with sequential guard clauses. Each failed rule returns an error message; only a valid password reaches the final success return.
function validatePassword(password) {
if (password.length < 8) {
return "Password must be at least 8 characters.";
}
if (!/[0-9]/.test(password)) {
return "Password must contain at least one number.";
}
return "Password is valid.";
}
console.log(validatePassword("abc"));
console.log(validatePassword("abcdefgh"));
console.log(validatePassword("abcdefg1"));
function validatePassword(password) { declares a function with one parameter, the password to check.if (password.length < 8) { checks whether the password has fewer than 8 characters. .length gives the number of characters.return "Password must be at least 8 characters."; returns this message and ends the function, so the later rules are not checked for a password that is too short.} closes the first if block.if (!/[0-9]/.test(password)) { uses a regular expression. /[0-9]/ matches any one digit, and .test(password) returns true if the password contains one. The ! reverses it, so the condition is true when the password has no digit.return "Password must contain at least one number."; returns this message for a long enough password without a digit.} closes the second if block.return "Password is valid."; is reached only if both rules passed.} ends the function body.validatePassword("abc") has only 3 characters, so rule 1 returns Password must be at least 8 characters.validatePassword("abcdefgh") is long enough, but has no digit, so rule 2 returns Password must contain at least one number.validatePassword("abcdefg1") has 8 characters including a digit, so both rules pass and the output is Password is valid.Common Mistakes With return
- Confusing
console.logwithreturn, and expecting a logged value to be usable elsewhere. - Writing code after a
returnstatement in the same block, not realizing it will never run. - Putting a newline between
returnand the value being returned, accidentally returningundefineddue to automatic semicolon insertion. - Forgetting to return a value at all, and being surprised the function’s result is
undefined. - Trying to return more than one separate value directly, instead of grouping them into an array or object.
Best Practices for return
- Use guard clauses with early
returnstatements to avoid deeply nested conditionals. - Always keep the returned expression on the same line as the
returnkeyword. - Return objects or arrays when a function needs to provide multiple related values.
- Prefer returning values from functions over relying on
console.logfor anything other than debugging. - Keep functions predictable — try to always return the same type of value from a given function, regardless of the input.
Quick Summary
returnsends a value back to the caller and immediately exits the function.returnwith no value returnsundefined.- A function without any
returnstatement also returnsundefined. - Guard clauses use early
returnstatements to simplify conditional logic. - Multiple values can be returned together using an array or object.
- Never place a newline between
returnand the value you intend to return.
Try It Yourself
Modify the function below. Try adding another guard clause, or changing what gets returned for each condition.
What this code does: Practice example: change the temperature thresholds or labels, then click Test My Code to see how early returns classify different values.
function classifyTemperature(celsius) {
if (celsius < 0) {
return "Freezing";
}
if (celsius < 15) {
return "Cold";
}
if (celsius < 25) {
return "Mild";
}
return "Hot";
}
console.log(classifyTemperature(-5));
console.log(classifyTemperature(20));
console.log(classifyTemperature(30));
function classifyTemperature(celsius) { declares a function with one parameter, a temperature in degrees Celsius. Try changing the thresholds and labels in the lines below, or adding a new guard clause of your own.if (celsius < 0) { is the first check. It is true for temperatures below 0.return "Freezing"; returns the label and ends the function.} closes the first if block.if (celsius < 15) { is only reached when the temperature is 0 or more, so it means 0 up to 14.return "Cold"; returns this label for that range.} closes the second if block.if (celsius < 25) { is only reached when the temperature is 15 or more, so it means 15 up to 24.return "Mild"; returns this label for that range.} closes the third if block.return "Hot"; is reached by temperatures of 25 or more. No condition is needed, because all the other ranges have already returned.} ends the function body.classifyTemperature(-5) matches the first guard. The output is Freezing.classifyTemperature(20) fails the first two guards and matches the third. The output is Mild.classifyTemperature(30) passes through all three guards and reaches the final return. The output is Hot.Tip: If you’re debugging a function and its result is unexpectedlyundefined, check two things first: did you actually write areturnstatement, and is the value on the same line as thereturnkeyword?
Understanding return is essential before moving on
to closures, recursion, and more advanced JavaScript concepts.
🧪 Test Your JavaScript Code
Edit the code on the left and click “Run Code” to see the console output on the right.
Click “Run Code” to see the output here.
Code Explanation
The complete example stays visible. Use Previous and Next to move through its logical blocks.
Select Next to begin exploring the code.