Is there a benefit to using a return statement that returns nothing?
JavascriptRefactoringReturn ValueJavascript Problem Overview
I'm refactoring a large javascript document that I picked up from an open source project. A number of functions use inconsistent return statements. Here's a simple example of what I mean:
var func = function(param) {
if (!param) {
return;
}
// do stuff
return true;
}
Sometimes the functions return boolean, sometimes strings or other things. Usually they are inconsistently paired with a simple return;
statement inside of a conditional.
The problem is that the code is complex. It is a parser that uses a multitude of unique RegEx matches, creates and destroys DOM nodes on the fly, etc. Preliminary testing shows that, in the above example, I could change the return;
statement to become return false;
, but I'm concerned that I may not realize that it had a negative impact (i.e. some feature stopped working) on the script until much later.
So my questions: Is there a benefit to using a blank return statement? Could this have been intentionally coded this way or was it just lazy? Can I change them all to return false;
, or return null;
or do I need to dig through every call and find out what they are doing with the results of those functions?
Javascript Solutions
Solution 1 - Javascript
Using return
without a value will return the value undefined
.
If the value is evaluated as a boolean, undefined
will work as false
, but if the value for example is compared to false
, you will get a different behaviour:
var x; // x is undefined
alert(x); // shows "undefined"
alert(!x); // shows "true"
alert(x==false); // shows "false"
So, while the code should logically return true
or false
, not true
or undefined
, you can't just change return;
to return false;
without checking how the return value is used.
Solution 2 - Javascript
"Blank return" statements can be used to transfer the control back to the calling function (or stop executing a function for some reason - ex: validations etc). In most cases I use blank return statement is when I'm doing some kind of a validation. However, I make it a point to set some indicator as to why the execution of the function is stopped. For example, set the "innerText" property on a DIV element with the error message.
In the code above, it looks like it is a validation. The function returns a "true" if everything went well. It looks like the calling function parses the return value, and if it is "true", next step of statements (in the calling function) are executed.
It is a good practice to return "false" instead of a blank return in the above example. That way you make it all uniform and make life easy for other programmers.
You could fix such inconsistencies; however, make sure you test all the changes thoroughly. It is a good practice to test each change you make to the code, however small it may be.
Solution 3 - Javascript
What MIGHT be lost here (not direct with your example) is that you can then have a tri-state object:
var myfunc = function(testparam) {
if (typeof testparam === 'undefined') return;
if (testparam) {
return true;
}
else {
return false;
}
};
var thefirst = myfunc(true)
var thesecond = myfunc(false);
var thelast = myfunc();
alert("type:" + typeof thefirst+" value:"+thefirst);
alert("type:" + typeof thesecond+" value:"+thesecond);
alert("type:" + typeof thelast+" value:"+thelast);
these return:
> type:boolean:true
> type:boolean:false
> type:undefined:undefined
note: null would return false in this example myfunc(null);
Solution 4 - Javascript
There is no difference at all between return;
and return undefined;
. The result of calling both functions is to receive the value undefined
.
(There's a very small specification-level difference between a function body that terminates with return
vs. just falling off the end of the code, but it's nothing that can be detected in code.¹ Calling a function where execution falls off the end of the code also results in the value undefined
.)
"use strict";
// Implicit return of `undefined`
function x() {
return;
}
// Explicit return of `undefined`
function y() {
return undefined;
}
// Execution falls off the end
function z() {
}
console.log(typeof x() === "undefined"); // true
console.log(typeof y() === "undefined"); // true
console.log(typeof z() === "undefined"); // true
Unless, of course, something has shadowed undefined
. Which is still sadly possible (though not, gladly, at global scope). In that very edgy edge case, there's a difference:
"use strict";
(function() {
const undefined = 42;
// ^^^^^^^^^^^^^^^---- shadowing `undefined`
// Implicit return of `undefined`
function x() {
return;
}
// Explicit return of `undefined`
function y() {
return undefined;
}
// Execution falls off the end
function z() {
}
console.log(typeof x() === "undefined"); // true, `x` returns the canonical `undefined`
console.log(typeof y() === "undefined"); // false, `y` returns 42
console.log(typeof z() === "undefined"); // true, `z` (effectively) returns the canonical `undefined`
})();
¹ Using return
is an abrupt completion that [[Call]] converts to a normal completion w/value. Falling off the end of the code is a normal completion (spec) (that [[Call]] ensures supplies undefined
for the value). But again, this is a specification level difference, not something that's observable in code.
Solution 5 - Javascript
Changing your functions will actually alter the code because return;
and return false;
output different data types.
var test = function (x) {
if (!x) {
return;
}
else {
return false;
}
};
var a = test(true), b = test(false);
console.log(typeof b); // undefined
console.log(typeof a); // boolean