I found this code about recursion online
function countDownRecursive(n) {
if (n <= 0) {
console.log('Hooray')
return
}
console.log(n)
countDownRecursive(n - 1)
}
I am really confused about this code, why does it console.log("Hooray") and then return nothing? Can you explain it to me? Thank you so much.
you returned a null value, the function output type is void.
try this
if (n <= 0) {
console.log('Hooray')
return n
}
return in this context means you don't want to continue running the function (similar to break in iterations).
The above recursive function's logic can be converted to this below while logic.
let n = 3;
//iterate until found the while break
while (true) {
//the condition to stop
if (n <= 0) {
console.log('Hooray');
break; //stop `while`
}
console.log(n)
n = n - 1;
}
why does it console.log("Hooray")
Because the function is recursive and when you start with let's say n=1 the function will not print "Hooray" immediately, because the condition:
if (n <= 0)
does not apply i.e. is false.
By the time we reach the recursion:
countDownRecursive(n - 1)
We call the function again with n=0 due to n - 1, the if-statement will evaluate to true and therefore print "Hooray".
and then return nothing
It does not actually return "nothing", even though the return type is void, it returns undefined, which is the default behavior for return you could also write return undefined instead.
When you use return, it will basically terminate or return from the current function. It will jump back into the scope where you did call the function initially.
Hope that clears it up for you.
Let's do it with an example. This is the hierarchy of the calls when n = 5
countDownRecursive(5) // "5"
countDownRecursive(4) // "4"
countDownRecursive(3) // "3"
countDownRecursive(2) // "2"
countDownRecursive(1) // "1"
countDownRecursive(0) // "Hooray" because n == 0, we execute the return statement
end of countDownRecursive(0) because of return
end of countDownRecursive(1) because reaching the end
end of countDownRecursive(2) because reaching the end
end of countDownRecursive(3) because reaching the end
end of countDownRecursive(4) because reaching the end
end of countDownRecursive(5) because reaching the end
The returns statement tells the program to stop calling itself
Related
I have one simple recursive function which adds all it's previous numbers.
function add(n) {
if (n == 0) {
return 1; // when it reaches here it should give me 1.
}
return n + add(n - 1);
}
console.log( add(5) ); // give me 16
when the execution reaches line number 3, it should return me 1, but it is return me 16. how return is actually working here ?
Recursion pauses the program at recursion step call and continue solving the sub problem and when a base condition is hit all the return statements pass the control back to the callee statement.
So
add(5)-->return 5+add(4)
|-->return 4+add(3)
|-->return 3+add(2)
|-->return 2+add(1)
|-->return 1+add(0)//base condition, return 1 for add(0) which in return return 2
1-->2-->4-->7-->11-->16 (In reverse)
that is because the conditional statement that your line 3 is in says to return 1 only if the argument n passed in is equals to 0. The function you are calling at the end of the code is passing in an argument of 5.
the first return statement would only work if condition in the if statement is true, otherwise it goes to the second return which calls the function again within itself.
I am trying to simply find recursion factorial
function factorial(num, result) {
console.log('num', num)
if (num === 0) {
console.log('res ', result);
return result;
} else {
result = result * num;
console.log(result)
factorial(--num, result);
}
}
let res = factorial(3, 1)
console.log(res)
It is giving undefined, not sure why, need some help.
plnkr
Bside the missing return statement, some annotations:
Use a default value for the result. This enables to call the function without given a starting value and allows touse only a single parameter.
Take only one early exit of the recursive call, without using else in combination with return. The return statement omits the following else statement. Just go on with the code without an else part.
Return at the end of the function a recursive call to allow to use the compiler to take a TCO (tail call optimization). This wotks without extending the stack, because the last call is replace with the actual recursive call. This optimization may not actually implemented.
Do not use decrement operators, if you need only the reduced value without using the reduced value again.
Move the calculation into the function call.
function factorial(num, result = 1) {
console.log('num', num);
if (num === 0) return result;
return factorial(num - 1, result * num);
}
console.log(factorial(3))
I'm back again. I had this little question about a possibility that I could declare a variable in the IF condition from a function, and to use it inside the statement itself.
Ok so, I'm curious to see if there's a way to declare a variable inside an IF statement's condition, and use that further along the statement as follows:
function SomeFunc() {return true}
if (let n = SomeFunc()) {
console.log(n); // true
// n is truthy
} else {
// Would never run, because it always returns true.
// This is just an example though, where it can return a truthy or falsy value dependent on the input context I could give it.
console.log(n); // false (if it actually returned 'false')
// n is falsy
}
Is there any way to do this, without having to run the function twice and not have it run outside the IF statement?
(Not like this though):
let n = SomeFunc();
if (n) { ... } else { ... }
// Or this:
if (SomeFunc()) {
let n = SomeFunc();
} else { ... }
I'd like to have one function being declared inside the condition, to minimalise line usage and have it - for me - clean. I hope there's a way to declare a variable inside of an IF condition.
Thank you in advance.
~Q
The syntax does not allow let, const or var to appear at that position.
But you could just define the variable (without initialisation) and then do the if:
let n;
if (n = SomeFunc()) {
// n is truthy
} else {
// n is falsy
}
If you want to limit the scope of that variable just to that if, then put it inside a block:
// other code...
{
let n;
if (n = SomeFunc()) {
// n is truthy
} else {
// n is falsy
}
}
// other code...
Of course, if your function has no other code, then no extra block is needed: the function's block will apply.
Many will disagree with you that an assignment within an if condition is clean. Best practice is to avoid such side effects in a condition, although opinions differ on this. Still, it does not take more characters to write it as follows, and it looks cleaner to me:
{
let n = SomeFunc();
if (n) {
// n is truthy
} else {
// n is falsy
}
}
As function expression
One other approach is to use an immediately invoked function expression, to which you provide the function's return value as argument:
(n => {
if (n) {
// n is truthy
} else {
// n is falsy
}
})(SomeFunc());
Ternary Operator
For a terse syntax use ternary operator:
var/const/let variable = (condition) ? value if true : value if false
The parenthesis wrapped around the condition are optional.
Demo
/*
Condition: if (number is greater than 10) ?
return true
: else return false
*/
const gTTen = number => { return (number > 10) ? true : false; }
console.log(gTTen(11));
console.log(gTTen(9));
function ternary(number) {
/*
Using the previous function then store its return in a
variable
*/
const tenFilter = gTTen(number);
/*
Condition: if (previous value is true AND the number is
less than 20) ?
range is 30
: else range is 0
*/
let range = (tenFilter && number < 20) ? 30 : 0;
/*
Condition: if (range = 30) ?
result is (the first string)
: else result is (the last string)
*/
let result = range === 30 ? `${number} is within range` : `${number} is not within range`;
return result;
}
console.log(ternary(50));
console.log(ternary(15));
Ah! I figured this out a few days ago, but didn't have time to respond. I could use local variables that I only overwrite while performing the statements.
Here's an example.
function retClone(bool) {
return bool; // Returns same input context for example.
}
if (t = retClone(true)) {
console.log(t); // true
// t is truthy, because we get `true` returned.
}
if (t = retClone(false)) {
// Wouldn't run.
// t is falsy.
} else {
console.log(t); // false
}
Thank you all who responded. ~Q
I posted a question not too long ago this morning regarding a kata that I was trying to solve. In that question, (found here if interested Kata Question) I needed to add a return statement to my function so that I would avoid the following error Value is not what was expected.
Now I have my second iteration of my kata solution to try out and here it is:
function isMerge(s, part1, part2) {
var pointer = 0
splitString = s.split('');
splitString.forEach(function(character) {
if (part1.includes(character) || part2.includes(character)) {
pointer++;
return true;
} else {
return false;
}
});
}
isMerge('codewars','cdw','oears')
I am still getting Value is not what was expected errors when I try to execute the code and this time I'm confused as to why in particular this happens.
For starters, taken from the MDN guide
The return statement ends function execution and specifies a value to be returned to the function caller.
expression
The expression to return. If omitted, undefined is returned instead.
Look at my if/else logic I am specifying a return true and return false condition in my forEach loop to see if all the chars from part1 and part2 are in the string. I am returning something so why is it that I have a Value is not what was expected?.
Second of all, by definition of the return statement, the function is supposed to stop when it reaches that keyword. However, when I place a console.log(character) in the logic, I can see on my console that all of the characters are being outputted so the function is not breaking at all when return true is executed. Why is that?
Third, I am confused as to when to use the return keyword in general. Consider these examples from the MDN docs for ForEach.
Example 1:
function logArrayElements(element, index, array) {
console.log('a[' + index + '] = ' + element);
}
// Notice that index 2 is skipped since there is no item at
// that position in the array.
[2, 5, , 9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[1] = 5
// a[3] = 9
Example 2:
function Counter() {
this.sum = 0;
this.count = 0;
}
Counter.prototype.add = function(array) {
array.forEach(function(entry) {
this.sum += entry;
++this.count;
}, this);
// ^---- Note
};
var obj = new Counter();
obj.add([2, 5, 9]);
obj.count
// 3
obj.sum
// 16
Not a single return statement to in these examples.
Now look at this .every example.
function isBigEnough(element, index, array) {
return element >= 10;
}
[12, 5, 8, 130, 44].every(isBigEnough);
And finally, from my previous question, I need to add a second return statement like this to avoid the value error.
function isBigEnough(element, index, array) {
return element >= 10;
}
function whenToUseReturn(array) {
return array.every(isBigEnough);
}
whenToUseReturn([12, 5, 8, 130, 44]);
So....... in conclusion, for my original function that started this how am I supposed to exit the loop when I reach false and return it and likewise when all the characters are in the string, how do I return a 'cumulative' true and avoid a Value error. I hope this makes sense and I can clarify with edits to better illustrate my point.
I am returning something so why is it that I have a Value is not what was expected?.
The return statement returns from the callback you pass to forEach, not from isMerge. return statements don't cross function boundaries. isMerge doesn't contain a return statement, hence it returns undefined. If we rewrite the function slightly it might become clearer:
function doSomething(part1, part2) {
return function(character) {
if (part1.includes(character) || part2.includes(character)) {
return true;
} else {
return false;
}
}
}
function isMerge(s, part1, part2) {
splitString = s.split('');
splitString.forEach(doSomething(part1, part2));
}
isMerge('codewars','cdw','oears')
This is equivalent to your code. As you can see, there is no return statement in isMerge.
Not a single return statement to in these examples.
There are no return statements in the forEach examples because forEach doesn't do anything with the return value of the callback, so there is no point in returning anything.
forEach is just a different way to iterate over an array, but it doesn't produce a value like reduce or every.
how am I supposed to exit the loop when I reach false and return it and likewise when all the characters are in the string, how do I return a 'cumulative' true and avoid a Value error.
You cannot exit a forEach "loop". If you have to stop the iteration early, you need to use a normal for (for/in, for/of) loop.
To return and produce a value, you can use your original solution that uses every.
My friend, since you decided to go the "callback way" using .each and the like, you should consider using callbacks, since you cannot return anything in this case. If you do not wish to go the callback way, just use standard javascript, such as:
splitString.forEach(function(character) {
Replace with
for(var i = 0 ; i < splitString.length; i++){
And now you can return. Using "each" to loop an array is just plain unnecessary and prevents you to return.
I am trying to learn recursive functions in JS but for some reason the result is undefined I want to alert (4,3,2,1,0) respectively.
function someFun(number) {
if (number < 0) {
return 1;
}
else {
alert(number = someFun(number - 1))
}
}
someFun(4)
Your function only has one return statement in it. When the else path of the if statement is taken, nothing is returned.
That said, you really don't need a return value because you just want the sequence of numbers printed (in descending order):
function someFun(number) {
if (number >= 0) {
alert(number);
someFun(number - 1);
}
}
someFun(4);
If you want the numbers printed in ascending order, you'd just reverse the order of the alert() and the recursive call.