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
Related
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())
assuming that an input was not equal to 1 or 2 (e.g. an input of 15), it would go through the loop, return false, but wouldn't that return value be overridden by the 'return true' underneath it that's outside of the for loop?
help to understand this would be much appreciated.
function checkIfPrime(numb) {
if (numb === 1) {
return false;
} else if (numb === 2) {
return true;
} else {
for (let x = 2; x < numb; x++) {
if (numb % x === 0) {
return false;
}
}
return true;
}
}
console.log(checkIfPrime(2));
console.log(checkIfPrime(15));
console.log(checkIfPrime(17));
console.log(checkIfPrime(19));
wouldn't that return value be overridden by the 'return true' underneath?
Well, no. When you return false the entire function execution stops and the return value is returned.
You give the example of numb = 15. Obviously 15 is not a prime number. The function will return false once x =3 within the for-loop. At this point the function execution will terminate completely and return the value false. It will not progress to the return true statement at all.
For a prime number example, say numb= 17, the for loop will execute and the if-statement will never be true. This means the function execution will progress and the return true statement will be executed, thus making the function return true.
Check out this W3 Schools documentation for furter explanation of the return statement.
As T.J. Crowder suggested in the comments, using your IDE's debugger would be useful for you to follow the execution.
when return statement is executed, statements after return are not executed. Program leaves the function and go to the statement calling that function.
return is different from a break; it doesn't just break out of the loop, but return the value for the whole function. Hope this helps.
Gav.
return is a terminator so the current code block exits upon meeting the statement
the behaviour you are describing would be created by this code
function incorrectCheckIfPrime(numb) {
var returnValue;
if (numb === 1) {
returnValue = false;
} else if (numb === 2) {
returnValue = true;
} else {
for (let x = 2; x < numb; x++) {
if (numb % x === 0) {
returnValue = false;
}
}
returnValue =true;
}
return returnValue;
}
console.log(checkIfPrime(2));
console.log(checkIfPrime(15));
console.log(checkIfPrime(17));
console.log(checkIfPrime(19));
In one of Douglas Crockford speeches, He favours the use of tail recursion over loops. this code was presented,
function repeat(myFunc) {
if (myFunc !== undefined) {
return repeat(myFunc);
}
}
I thought to define a myFunc but don't know if a static counter can retain its state during function calls or use a global counter. but being new to javascript I wanted to ask first. How can this be used in an example, say to count down from 10 to 0? Thanks.
You need to call the function myFunc somewhere -- and evaluate the result for further call of repeat.
function repeat(myFunc) {
if (myFunc()) {
repeat(myFunc);
}
}
var count = 10;
repeat(function () {
document.write(count + '<br>');
count--;
return count >= 0;
});
Here is a version that keeps state without global variable:
function repeat(myFunc, arg) {
if ((arg = myFunc(arg)) !== undefined) {
repeat(myFunc, arg);
}
}
repeat(function (count) {
document.write(count + ',');
count--;
if (count >= 0) return count;
}, 10);
How can this be used in an example, say to count down from 10 to 0?
Pass a Number to repeat, call repeat with decremented number as parameter until variable parameter is equal to 0
function repeat(n) {
console.log(n)
if (n) {
return repeat(--n);
}
}
repeat(10)
Not sure if I understand what approach you want, but you can use this to count down recursively
function repeat(myFunc, times) {
if(times > 0 && typeof myFunc == 'function') {
myFunc(times);
repeat(myFunc, times-1);
}
}
repeat(alert, 10);
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.
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;
}