I have often wondered if it is bad practice to allow sequential execution to decide the return value and termination point. EG (this is a question surrounding IF statements, so ignore the fact there are myriad better ways to do this simple function!):
function isGreaterthanTen(val) {
if(val > 10) return true;
return false;
}
Same effect, is smaller but maybe less readable than:
function isGreaterthanTen(val) {
if(val > 10) {
return true;
} else {
return false;
}
}
So is one better than the other, best practice wise and/or min-wise?
You should avoid writing so called spaghetti code. That means, one should be able to read your code without jumping from one place to another in order to untangle and understand it. Having return statement in the middle of your code can be considered a spaghetti code, especially in longer functions.
I prefer having one return statement that returns a variable, which I declare at the top of the function and manipulate throughout the execution.
function isGreaterthanTen(val) {
let isGreater = false;
if (val > 10) {
isGreater = true;
}
return isGreater;
}
of course that function can be shortened to:
function isGreaterthanTen(val) {
return val > 10;
}
A one exception from this rule which I'd allow is at the top of the function when you validate the data and prevent the execution:
function isGreaterthanTen(val) {
if (typeof val !== 'number')
return;
return val > 10;
}
which fill return nothing if the parameter isn't a number.
At my current work - Leads never advise to use single line execution without brackets stating readability lacks there.
if(true) {
return 'good practice'
}
if(true)
return 'bad practice'
Another related point I always follow is checking for negative value first
if(false) {
return 'this is the negative case'
}
return 'case for most of the positive case'
However I know different ways to just handle such single line returns
If just boolean than you can simply return the condition
function foo(){
return 1 === 1
}
console.log(foo())
You can use coerced value for just boolean value if your value is treated as truthy or falsy and not a boolean
function foo() {
return !!1 // 1 treated as true
}
console.log(foo())
If you have two different values to get returned so you probably use ternary too.
function foo() {
const me = 'satyam',
friend = 'jack',
satyamAge = 23
return satyamAge === 20 ? me : friend
}
console.log(foo())
Related
I'm studying Javascript basics, particularly higher order functions, at the moment. I have read many articles and watched as many videos where people explain the basic definition and demonstrate the most basic construction of a higher order function. However, when I encounter an actual problem, I am lost. Here is an example (this is just for my personal study, not for a grade or for work):
Write a maybe function that, given a predicate (a function that returns a boolean value) and any other function, only calls the latter if the former returns true: maybe(x => x > 100, myFn). If the predicate returns true, the value of x should be passed to myFn. If the predicate returns false, x should be returned unchanged.
I don't understand how to pass the value of x from one function to another...
I solved this by adding a number argument to maybe, in addition to the predicate function and callback function. However, only two parameters are specified in the prompt, so I guess I'm not doing it correctly. Here is what I did:
//predicate (evaluates to a boolean)
const notZero = function(x) {
//console.log('predicate runs!');
return x !== 0;
}
//callback (does something within the main function)
const plusOne = function(x) {
//console.log('callback runs!');
return x + 1;
}
//checking if my predicate works
//test(notZero(1), true); // => test passed!
//another callback
const myFn = function(x) {
return x - 100;
}
//main function
function maybe(number, predicate, callback) {
if (predicate(number) === true) {
//console.log('predicate === true');
//console.log(callback(number));
return callback(number);
} else {
return number;
}
}
test(maybe(1, notZero, plusOne), 2);
test(maybe(0, notZero, plusOne), 0);
test(maybe(101, x => x > 100, myFn), 1);
test(maybe(99, x => x > 100, myFn), 99);
EDIT: As shared below, maybe can now take only 2 parameters (the predicate and the callback) because it now returns a function whose parameter is number. That's the idea I was looking for.
function maybe(predicate, callback) {
return function (number) {
if (predicate(number) === true) {
return callback(number);
} else {
return number;
}
}
}
It's technically impossible. x is locked out of the world in predicate's scope. There's no way you may extract it out of this function.
Apart from that, as you correctly assume in your code, we logically need to communicate x to both predicate & callback. Otherwise, what's the point of maybe at all?
Since then, your solution is one of very few possible ones.
You may "decorate" it nicer with currying. The idea is precisely identical as in your code but if you'll do so, you will be able to call the final function exactly with 2 arguments.
const setMaybeBase => x => (predicate, callback) => predicate(x) ? callback(x) : x;
// use it later this way
const maybe42 = setMaybeBase(42);
maybe42(yourFn, yourFnTwo);
This is a huge overkill unless the argument you pass to setMaybeBase is for example a complex object you are going to work with.
Alternatively, you might go wild & use a function to get the x as well.
Nevertheless, always remember that the easiest solution is the best one.
Here is a real-world example of maybe function taken straight from node.js repo:
function maybeCallback(cb) {
if (typeof cb === 'function')
return cb;
throw new ERR_INVALID_CALLBACK(cb);
}
I'm trying to write a function that checks if a number "N" is even or odd by subtracting 2 until it gets to 1 or 0. A final value of 0 represents even. The goal here is to use a recursive function to reach the final result, but I'm having some issues where all I have returned are undefined.
This is what I have so far.
function isEven(number) {
function subTwo(number) {
if (number == 0) {
return true;
}
else if (number == 1) {
return false;
}
else if (number > 0) {
number -= 2;
subTwo();
}
else {
console.log("bruh");
}
};
};
console.log(isEven(50));
// → true
console.log(isEven(75));
// → false
console.log(isEven(-1));
// → ??
Does anyone see what I'm doing wrong or have any advice for me?
Thanks.
EDIT:
Thanks for the help guys. It was suggested that I remove subTwo completely and use isEven as the recursive function, and that I had to use return isEven(number) within the second if/else statement.
Both of those suggestions together helped the code compile correctly.
Thanks a ton guys, although I'm not sure why I got downvoted lol.
Your problem is here:
subTwo();
You need to pass the current version of number into it: subTwo(number); and return it.
you could also fix the problem by omitting the parameter in the internal function, like so: function subTwo(){...} The internal function already has access to the parent function's parameter (closure), so you don't need to pass that into the internal one.
also, this is not returning anything, it's just logging. JavaScript always returns something. If you don't say return "something", it returns undefined.
else {
console.log("bruh");
}
Personally, I would also rework you code like so:
function subTwo(number) {
if (number > 0) {
number -= 2;
subTwo();
}
else if (number == 1) {
return false;
}
else if (number == 0) {
return true;
}
else {
console.log("bruh");
}
};
The statements are then in descending order, so you can quickly see the progression. It helps people look and see if anything has been missed.
The problem is that you define the function subTwo but it's never actually called when isEven is called. A simpler version would be to not even have another function and do it all with recursive calls of isEven
function isEven(number) {
if (number === 0) {
return true;
} else if (number === 1) {
return false;
} else {
return isEven(number - 2)
}
}
EDIT
Alternatively, if you really want the additional function, notice that you defined subTwo to take in a parameter but you did not pass in the parameter when recursively calling it via subTwo();. Also, when you recursively call subTwo(number), make sure you actually have return subTwo(number) so the value is returned at each recursive call. Additionally, you need to actually call the function and return the result when isEven(number) is called via a return statement and wrapping the function in brackets and calling it with number or manually calling it using return subTwo(number). See below for an example of how you would return at each stage so it passes it all the back up to the original call of isEven(number):
function isEven(number) {
return (function subTwo(number) {
if (number === 0) {
return true;
}
else if (number === 1) {
return false;
}
else if (number > 0) {
number -= 2;
return subTwo(number);
}
else {
console.log("bruh");
}
})(number);
};
As was said in the comments you never check for a value less than 0. What happens is when you enter the value -1 is it jumps down to the else part of your code. The part that says "console.log("bruh");" After completing that line the program keeps going and returns... nothing. You dont return anything, hence why you get undefined. You should set up your code to handle the case when a negative number is passed in.
Is it possible to know if a function uses an empty return statement versus simply not using the return keyword?
For example:
function noReturn(){ }
function useReturn(){ return; }
console.log( noReturn() ); // undefined
console.log( useReturn() ); // undefined
I know all about WHEN and WHY one would use an empty return statement, I just want to know if you can tell if return; was used at all versus no return statement.
I'm assuming that its not possible, and thats ok. If there was any cool Function prototype trick I didn't know of, that would be sweet.
Edit: Not trying to solve any particular problem, unless general curiosity is a problem. :)
You cannot distinguish return values of these three functions:
function a() { }
function b() { return; }
function c() { return undefined; }
according to JS specification.
No, it's not possible to differentiate these:
return undefined;
return;
End of function without returning any value
First, both return undefined; and return; return the same:
12.9 The return Statement
ReturnStatement :
return ;
return [no LineTerminator here] Expression ;
A return statement causes a function to cease execution and return a
value to the caller. If Expression is omitted, the return value is
undefined. Otherwise, the return value is the value of Expression.
A ReturnStatement is evaluated as follows:
If the Expression is not present, return (return, undefined, empty).
Let exprRef be the result of evaluating Expression.
Return (return, GetValue(exprRef), empty).
And then, it does not matter if you used return; or nothing, because [[Call]] will return undefined:
13.2.1 [[Call]]
If result.type is throw then throw result.value.
If result.type is return then return result.value.
Otherwise result.type must be normal. Return undefined.
I think this is a toy problem, but here is a possible approach to this problem. Convert the function to a string, then for all instances of a valid return statement anywhere in the string replace them with confederate return statements. Execute this modified function using eval() and observe what is returned.
For example,
function foo(){ return; }
function bar(){ if(0) return; }
becomes
function foo(){ return 'return;'; } // "return;"
function bar(){ if(0) return 'return'; } // undefined
This way whatever path the logic follows in the function, if something is explicitly returned, we can know what form it takes. If nothing is returned, due to design or logic flow, then 'undefined' is returned. Consider the following function:
function inspectReturn(fcn) {
var str = fcn.toString();
// Anytime we see a 'return something' we replace it with return 'something'
str = str.replace(/(\b)return \s*(\S[^\n;}]+)/mg, "$1return '$2'");
// Anywhere we see a lone 'return' we replace it with return 'return'
str = str.replace(/(\b)return\s*([\n;}])/mg, "$1return 'return;'$2");
eval("fcn="+str);
return fcn();
}
We can then observe the return values from the the below sample functions:
function noReturn(){ } // undefined
function useReturn(){ return } // "return;"
function useReturn2(){ return; } // "return;"
function useReturn3(){ return true; } // "true"
function useReturn4(){ if(0) return; } // undefined
function useReturn5(){ return undefined } // "undefined "
function useReturn6(){ var _return = " return "; return _return; } // "_return"
Demo: JSBin
Note: Voice your opinion about how the regex can be improved all you wish. You might be able to break it (and congratulations to you), but there are simple and concrete JavaScript parsing rules for validating return statements, so on such a toy problem it's up to the reader to properly implement them. Also, if something is thrown, then catch blocks exist for that. However, this is a sufficient demo IMHO.
Quite apart from knowing that JavaScript does not differentiate these. A way for checking might be:
function noReturn(){ }
function useReturn(){ return; }
function foo(){
var _return = "return";
}
function fooReturn(){
var _return = "return";
return _return;
}
function fooReturn2(){
var _return = "return";
return;
}
console.log(/return\s*(\w*);?\s*}\s*/.test(noReturn.toString())); //false
console.log(/return\s*(\w*);?\s*}\s*/.test(useReturn.toString())); //true
console.log(/return\s*(\w*);?\s*}\s*/.test(foo.toString())); //false
console.log(/return\s*(\w*);?\s*}\s*/.test(fooReturn.toString())); //true
console.log(/return\s*(\w*);?\s*}\s*/.test(fooReturn2.toString())); //true
My broad question is what's the simplest way to differentiate between an initial and successive call to a recursive function in JavaScript.
Lemme give an example...
Let's say I want the following function to return false if the string passed to the function in the initial call is empty. Is there a way to do this without adding in another parameter to the function?
function isPalindrome(str) {
if (str.length <= 1) {
return true;
}
if (str.charAt(0) !== str.charAt(str.length -1)) {
return false;
}
return isPalindrome(str.substr(1, str.length - 2));
}
isPalindrome('') // returns true, but I want this to return false
Btw, I know the above function could be written more simply as:
function isPalindrome(str) {
return str == str.split('').reverse().join('');
}
But I'm reframing it as a recursive function to get at the broader question here...
Don't try to distinguish different calls - the result of the function should not depend on side effects and definitely not on the call stack.
Instead, use a second function that does a little different thing:
function isPalindrome(str) {
return str.length <= 1 ||
str.charAt(0) == str.charAt(str.length-1) && isPalindrome(str.slice(1, -1));
}
function isNonEmptyPalindrome(str) {
return str.length > 0 && isPalindrome(str);
}
You can have a nested function, even with the same name:
function isPalindrome(str) {
// The code out here is for the initial call:
if (str === '')
return false;
// Then do the recursive call
return function isPalindrome(str) {
// within this scope, isPalindrome refers to this function
if (str.length <= 1) {
return true;
}
if (str.charAt(0) !== str.charAt(str.length -1)) {
return false;
}
return isPalindrome(str.substr(1, str.length - 2));
}(str); // call this function immediately
}
For a general form:
function name(arg) {
// Setup code before initial call
//////////////////////////////
var retVal = function name(arg) {
// recursive routine code
}(arg);
// Cleanup code after recursion completes
/////////////////////////////////////////
return retVal;
}
Demo using factorial
This is essentially the same as Bergi's answer but with the helper function declared inside isPalindrome so that it isn't used elsewhere.
A better example for a palindrome is that all punctuation should be removed and letters made all upper or lower case (so that comparisons are not case sensitive), but only on the first call. After that, it's a simple matter of comparing characters.
The length == zero part is also only handled once, the function isn't called recursively if there are no characters left to compare.
The following does initial processing, then calls an inner function.
A function declaration is used instead of a named function expression as the latter have undesirable side effects in IE.
function isPalindrome(s) {
// Initial processing only on first call
// remove all punctuation
s = s.replace(/[^a-z0-9]/ig,'').toLowerCase();
return s.length == 0? false : doCheck(s);
function doCheck(s) {
if (s.length > 1) {
if (s.substr(0,1) == s.substr(s.length - 1, 1)) {
s = s.substr(1, s.length - 2);
return s.length? doCheck(s) : true;
} else {
return false;
}
}
return true;
}
}
console.log(isPalindrome("Madam I'm Adam")); // true
console.log(isPalindrome("Madam I'm Addam")); // false
Having the following code:
function test(x) {
if(x=='a') return false;
return true;
}
if(y ==x) {
return test('a');
group['ids']= inputs.val();
console.log(group);
}
why return true simply breaks my code by not continuing beyond the return?
Note: I want the return test()'s answer to control if either it should continue with the code OR not
Update
I already do something like:
var response = test('b');
if (response==false) return false;
... more code here ...
But I want to avoid having to do so on every invoke of that function
Because that's what return does in almost every programming language: it
exits the function and
returns a value
If you need other code to be executed, put it before the return statement.
Edit: I saw your edit, but it doesn't change the very nature of return in that (and every) context. It will continue to stop the flow of the current scope, returning to the nearest higher scope with a value (in your case, true or false).
The keyword return, as it name suggests, returns the program flow control to the calling function and optionally sets the function's return value.
This works the same way in every C-like language.
What you probably wanted to do is a Delphi-like approach, where the keyword Result works differently - it just sets the return value that will be used when the function terminates, but does not immediately terminate the function.
function() {
var result = someDefaultValue;
if (someCondition)
result = otherValue;
if (otherCondition)
result = yetAnotherValue;
return result;
}
try putting return at the end because return true will break the execution and nothing will execute after that
When a return statement executes, the execution of the current function ends, and control of the program is returned to the context that invoked the function. Anything after a return statement will not be executed.
The return keyword causes a function to end ('return') when the interpreter reaches that keyword and does not continue to process anything after the return statement (in that same function).
You could rewrite what you have:
group['ids']= inputs.val();
console.log(group);
return true;
I typically find out which scenarios are bad/errors and return false; out of them, THEN continue on to the code which is correct.
function Testmcdooder (test) {
if (test === false) {
// just exit up here
return false;
}
// now all of this code will run only if we're fine
group['ids']= inputs.val();
console.log(group);
}
The return statement exists from the function. I think that you rather want an if statement:
if (y == x) {
if (test('a')) {
group['ids']= inputs.val();
console.log(group);
}
}
If you also want to return the value after determining if the other statemens should run:
if (y == x) {
if (test('a')) {
group['ids']= inputs.val();
console.log(group);
return true;
} else {
return false;
}
}
Alternatively:
if (y == x) {
var cond = test('a');
if (cond) {
group['ids']= inputs.val();
console.log(group);
}
return cond;
}