Recently, a friends asked me a question: “What does ‘return’ mean in JavaScript?”
function contains(px, py, x, y) {
const d = dist(px, py, x, y);
if (d > 20) return true; // What does this line mean?
else return false; // How about this line?
}
Initially, I thought this would be a straightforward question, but it turned out to have some important and interesting concepts behind it!
Two kinds of functions
I first explained the difference between functions with and without a return statement. Functions are set of instructions. If you need the result of executing these instructions, you need a return statement. Otherwise, you don’t.
For example, to get the sum of two numbers, you should declare an add function with a return statement:
function add(x, y) {
return x + y; // with a return statement
}
You can then use the add function like this:
const a = 1;
const b = 2;
const c = add(a, b); // 3
const d = add(b, c); // 5
If you simply want to log a message to the console, you don’t need a return statement in your function:
function great(name) {
console.log(`Hello ${name}!`);
}
You can then use the great function like this:
great("Rachel");
I thought I’d already solved my friend’s question so far, but she posed a new one: “Why do we need the sum function? We can write a + b everywhere, then why bother with a return statement?”
const a = 1;
const b = 2;
const c = a + b; // 3
const d = b + c; // 5
At that point, I realized that the her true question was “Why do we need functions?”
Why functions?
Why use functions? While experienced programmers have numerous reasons, I’ll focus on those relevant to my friend’s question. Let’s explore the key benefits that address her curiosity.
Reusable Code
She’s right. We can easily write a + b everywhere. However, this is only because addition is a simple operation. What if you want to perform a more complex calculation?
const a = 1;
const b = 2;
// Is this easy to write everywhere?
const c = 0.6 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
What if you need more than one statement to get the result?
const a = 1;
const b = 2;
// t is a temp variable
const t = 0.6 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
const c = t ** 2;
In both situations, writing this repeatedly becomes cumbersome. For such reusable code, you can encapsulate it in a function. This way, you don’t have to rewrite the implementations every time you need it!
function theta(a, b) {
return 0.6 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
}
const a = 1;
const b = 2;
const c = theta(a, b);
const d = theta(b, c);
Maintainable
When discussing reusability, you can’t overlook maintainability. The only unchanged thing for the world is that the world is always changing. And this applies to code as well! The easier it is to modify you existing code, the more maintainable it becomes.
What if you want to change 0.6 to 0.8 when computing the result? Without a function, you’d have to change every places where you perform the computation. But with a function, you only need to change one place: inside the function itself!
function theta(a, b) {
// change 0.6 to 0.8, and you done!
return 0.8 + 0.2 * Math.cos(a * 6.0 + Math.cos(d * 8.0 + b));
}
Functions undoubtedly enhance code maintainability. Just when I thought resolved her inquiry, she posed another thought-provoking question: “I understand the need for functions, but why do we need to write ‘return’?”
Why return?
Fascinating! I hadn’t considered this question before! She then proposed some alternative solutions for ‘return’, which I found incredibly creative!
Why not just returning the last statement?
The first proposed solution is “Why not just returning the last statement?”
function add(a, b) {
a + b;
}
const sum = add(1, 2); // undefined
As we know, this is not allowed in JavaScript, Java, C, or many other languages. The specifications for those language requires an explicit return statement. However, it is allowed in some language, such as Rust:
fn add(a: i32, b: i32) -> i32 {
a + b
}
let sum = add(1, 2); // 3
However, it’s worth noting that another type of function in JavaScript doesn’t require a return statement! That is the **Arrow Function** with a single expression:
const add = (x, y) => x + y;
const sum = add(1, 2); // 3
What if we assign the result to a local variable?
She then offered another creative solution: “What if we assign the result to a local variable”?
function add(x, y) {
let sum = x + y;
}
add(1, 2);
sum; // Uncaught ReferenceError: sum is not defined
She quickly noticed that we can’t access to the sum variable. This is because the variables declared with the let keyword are only visible within their defined scope—in this case, the function scope.
Think of functions as black boxes. You put things into the boxes (parameters), and expect to get something out (the return value). Only the return value is visible (or accessible) to the outside world (the parent scope).
How about assigning to a global variable?
What if we access the value outside the function’s scope? How about assigning it to a global variable?
let sum;
function add(x, y) {
sum = x + y;
}
add(1, 2);
sum; // 3
Oh, muting a global variable! Side effect! Not a pure function! Theses thoughts raced through my mind. But how can I explain why this is a poor choice in just a minute?
One key reason to avoid this approach is that it’s difficult for others to know which global variable is modified within a specific function. They’d have to search for where they can find the result, rather than obtaining it directly from the function!
Summary
In a nutshell, we need ‘return’ because we need functions, and there no viable alternatives in JavaScript for standard functions.
Functions exist to make code reusable and maintainable. Due to the specification of JavaScript, the limitations of function scope, and the risks associated with modifying global variables, we must use the return statement for standard functions in JavaScript.
This discussion is so fascinating! I never imagined that such a seemingly simple question could harbor so many intricate considerations. Engaging with people from different perspectives always bring new insights to light!