Recursive javascript function causing "Maximum call stack size exceeded" - javascript

During the course of designing a small API at work and trying to make my functions as flexible as possible I decided to start adding checks for whether arguments are passed, and then based on that, do different things. So when the function is called with a number, the function uses the number as an index in an array. If no number is passed, I wanted the function to call itself as many times as the length of the array. However I get the call stack error. I have boiled the problem down to the recursion aspect of the function, which I'm listing below. The thing that is strangest to me is this...
THIS CAUSES ERROR
function testing(a){
if(!a){
for(var i = 0; i < 3; i += 1){
testing(i);
}
}else{
alert(a);
}
}
testing();
THIS DOES NOT CAUSE ERROR
function testing(a){
if(!a){
for(var i = 0; i < 3; i += 1){
testing(5);//Just adding hard coded number instead
}
}else{
alert(a);
}
}
testing();
I'm trying to understand why passing the var in the call throws an error. It seems that if the js engine can hold the initial function call in memory in order to make the for loop work properly why couldn't it hold a reference to i while calling itself? I feel like I am missing something fundamental here. I've tried lots of rewrites involving things like:
testing(function(i){return i;}(i));
All to no avail. This is driving me crazy and I would like to understand what is going on here.

if a===0 it is false, that means you have an infinite loop
for more details, read this and this (thanks #yochannah )

This works just fine.
function testing(a){
if(!a || a == 0){
for(var i = 1; i <= 3; i++){
testing(i);
}
} else {
alert(a);
}
};
testing();
Obviously there's no need to both start the loop counter off of 1 AND checking whether a == 0, but both methods would work.
EDIT: Another check you can have is (a == undefined).
The thing is that a variable that returns 0 is false when you check it with !.

Related

For loop skipping iterations

I have a for loop which will iterate through all choices and and set a value for them.
For some reason, when I run the code it does the first iteration, then skips to the last and does that one 3 times, or so according to the console.
code:
for (i = 0; i < 4; i += 1) {
console.log(i)
var generated = word
while (generated == word) {
generated = wordsJson.characters[Math.floor(Math.random() * wordsJson.characters.length)]
}
choices[i].innerHTML = translate(generated)
}
What I get in console:
0
(3) 3
This is my first time asking something on stackoverflow. If you need more information, please ask.
It appears that the variable i is getting modified outside of the for loop.
Typically you would want to declare your iterator variable (in this case i) so that it's scoped to the loop, which would look like:
for (let i = 0; i < 4; i += 1) { ... }
Note, specifically, the addition of let. Since you haven't done that, it means that either i is already explicitly declared somewhere or, if not, that you've created a new global variable i.
Since you've got code you haven't shown that also seems to relate to i (choices[i]) and methods that we don't know the exact function of (translate()) it's hard to say for certain, but that would be the first place to look.
If not, posting some additional code so we can see the other functionality would be helpful.

Initialisation statement in for loop

i want to know what happens when we don't use it
eg
for(;i<=10;i++)
{
}
I searched some sites but i am very confused.
Thanks.
Well first off, it will give an error saying that i is not defined. But if you declare it ahead of the loop, it works fine:
var i = 0;
for(;i<=10;i++){
console.log(i);
}
You can also remove the termination statement as well, and keep it in the loop like this :
var i = 0;
for(;i<=10;){
console.log(i);
i++;
}
It'll work, I hope that answers your question...
Its similar to a while loop where you initialize a variable first and then keep the loop with the comparison and the terminate it with a termination statement. So according to the code in your question, what you are basically do is something like this:
while(i <= 10){
console.log(i);
i++;
}
Which will give an error.

Loop through javascript functions

I have a series of numbered javascript functions and I would like to loop through the functions based on a variable called total. If total is 3, I would like to run load1(data), load2(data), load(3) data; if it is 2 just the first two functions so on.
This seems simple enough, but I can't seem to get it working right. In the simplest form the code below works.
i = 1;
if (i <= total){load1(data);}i++;
if (i <= total){load2(data);}i++;
if (i <= total){load3(data);}i++;
if (i <= total){load4(data);}i++;
if (i <= total){load5(data);}
But I can't seem to be able to put that in a loop. I have tried the following:
Trying to put the functions in an array and calling them in a for loop based on this thread. //throws a function undefined error.
Call it inside a loop like this:
var f = new Function("return load"+i+"(data)")(); //throws a data not defined error
Any suggestions?
If loadX is global function, you could do like below:
for (var i = 1; i <= total; i++) {
window['load'+i](data);
}

FizzBuzz in Javascript: the code won't execute or print at all

Have been playing around with the FizzBuzz problem, and I am wondering why the following code won't execute, nothing gets printed to the console.
var i = 0;
while (i = 0, i < 100, i++ ) {
if ( i % 3 === 0) {
console.log("Fizz");
} else if ( i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
What am I missing?
You used the wrong looping construct. It should be a for, not while. Also note that it's semicolons between the clauses, not commas:
for (i=0; i < 100; i++) {
What you have is this:
while (i = 0, i < 100, i++) {
The comma just evaluates the left side, throws the result away, and then evaluates the right side. So that sets i to 0 (and discards the zero value returned by the assignment), tests that i is less than 100 (but does nothing with the true value returned by the comparison), and uses the value of the last expression (i++) as the loop condition for the while. Since i is 0, which is falsy, the loop body never executes.
Note that if you had used ++i instead, it would make no difference in the for case, but your while version would loop forever instead of not running at all, since i would already have been incremented to 1 the first time it was tested for truthiness.
I believe you are simply confusing the way you make 'for' and 'while' loops. You've built your 'while' like you would a 'for'!
Think of it this way: when you write a while loop like this:
while(i<100) {
You're saying, while (this condition is true). All that you need between the parentheses is a statement to determine whether it's true or not. Somewhere in the loop, you (usually) would need to change the value of i, or you'd (probably) get an infinite loop.
Now, the for loop, we'll need more information between the parenthesis... we'll need all the information that determines the amount of loops we'll take. Just like you've written it there, we're writing for (when my variable equals this; Loop until this condition is true; change the variable like this).
Generally, this means that 'while' provides more flexibility in how you determine the logic of your loop, but a 'for' loop is probably the easiest to read.

Is there a loop "start-over"?

There is continue; to stop the loop and move to the next loop
There is break; to stop the loop and move to the end of the loop
Isn't there some kind of start; that stop the loop and move to the beginning of the loop?
I know it is easy to achieve all of these three actions by just modifying the value of i, but I always try to look for already built-it functions.
Resetting the value of your loop variable to the initial value then calling continue is as close as you'll get.
For example:
for(var i=0; i<20; i++) {
if(somecondition) {
i=-1; continue;
}
}
No - there is no keyword or other way to do it automatically.
As you already mentioned you can just modify the loop condition variable(s) within your loop. Easy if it's a simple i counter, but of course you may have more initialisation to do than just a simple counter.
Or you can do something like the following:
restartLoop:
while (true) {
for (var i=0, j=100000, x="test"; i < 1000; i++, j--, x+= ".") {
if (/*some condition, want to restart the loop*/)
continue restartLoop;
}
break;
}
The continue restartLoop will jump back out to continue with the next iteration of the while loop, which then immediately starts the for loop from the beginning including all of the initialisation code. If the for exits normally the break statement after it will break out of the containing while loop.
I don't really recommend doing this in a general sense, but if your loop initialisation process was really complicated it could be worth it because then you wouldn't need to repeat it all inside the loop. If you needed to do even more initialisation than fits nicely in the for statement's initialisation expression you can easily put it just before the for loop inside the while and it will all be re-run...
If you want to avoid jumps or the equivalent of goto statements that many of us have been trained to avoid, you could use a local function for the loop and a test on the return value to see if you should just call it again:
function doItAll() {
// put state variables other than the actual loop control here
function doTheLoop() {
for(var i=0; i<20; i++) {
if (somecondition) {
return(true); // run the loop again
}
}
return(false); // done running the loop
}
while (doTheLoop()) {}
// do some things after the loop
}
No. (Just to rule out a "I just haven't heard of it, either" - it isn't mentioned at https://developer.mozilla.org/en/JavaScript/Reference/Statements.)
continue works by simply skipping the rest of the loop body. break works by skipping the rest of the loop body and then ending the loop. A start function would have to somehow "rewind" the state of the program - but not all of the state of the program, since presumably you don't want to lose what you did, either - to where it was when the loop began, which is not something that any programming language that I have seen provides.
You could have the loop in a function that calls itself recursively:
function loopIt(numTimes) {
if (numTimes < 3) {
for (x = 0; x < 20; x++) {
if (x == 5) {
loopIt(numTimes+1);
break;
}
}
}
}
You can obviously change the conditions to fit you logic as the above is a simple example.

Categories