Pre-decrement operator in JavaScript while loop causes stack overflow - javascript

Recently I was going through some JavaScript code and at multiple places they are using a while loop to iterate over arrays. The way they do it is as
var i = dataArray.length;
while ( i-- ) {
// iterating over the array.
}
We know that the post-decrement operator here would first supply the value to while call and then will reduce it by one. So in this case for the first iteration if the array length is 10, the while call checks for i to be 10 and we get the value of i inside the loop to be 9. This continues till i reaches a value of 0 and then we exit out of loop. Precisely speaking we are iterating the array in a reverse manner.
This is fine. Where it really confuses me is when I write a pre-decrement operator, the while loop runs forever resulting in a stack overflow.
var i = dataArray.length;
while ( --i ){
// This loop would run forever.
}
Why is this happening? Won't doing --i will also result into i hitting the 0 value at some point of time and breaking the loop?

This is only the case if dataArray is empty. In that casen i = dataArray.length becomes zero. Then when you enter the while loop, i is pre-decremented to -1. Since all non-zero numbers evaluate to true, the loop keeps on going forever.
However, if the array has any elements, this will not happend and the loop will terminate. This code will illustrate the effect without craching anything:
function loop(x) {
var i = x.length;
while ( --i ) {
console.log(i);
if(i == -5) break; //Break after a while so we avoid an endless loop.
}
}
loop([]);
loop([1,1,1]);
The output of the first call is -1, -2, -3, -4, -5, and the output of the second call is 2, 1.
JSFiddle.

Ideal way of writing While loop.
while(condition){
// Your code
// iterator update (i++/i--)
}
Why you loop stops? JavaScript considers 0 as false and stops when reaches 0.
Also can't tell why predecrement runs forever. This might be because i never reaches 0;
Loop simulation
var data = [];
function createArray(){
for (var i=0; i<10; i++){
data.push(i);
}
}
function preDecrementLoop(){
var i = data.length;
while(--i){
console.log(i);
}
}
function postDecrementLoop(){
var i = data.length;
while(i--){
console.log(i);
}
}
(function(){
createArray();
console.log("pre decrement");
preDecrementLoop();
console.log("post decrement");
postDecrementLoop();
})()
Note: --i will skip loop for 0 since 0 is considered as false, while (0) == while (false).

Related

JavaScript: setInterval and for loop explanation

i searched around for a couple of questions related to the use of the for loop and the setInterval function in JavaScript but i couldn´t find a concrete answer on why this snippet doesn´t work. Could someone explain please what´s happening under the hood and why this code doesn´t print anything at all?
for (let i = 0; i++; i < 10) {
window.setInterval(function () {
console.log('Test');
} , 100)
}
Your for loop is not correct. The condition needs to be the second statement in the for loop.
Following code should work.
for (let i = 0; i < 10 ; i++; ) {
window.setInterval(function () {
console.log('Test');
} , 100)
}
Expected Syntax for loop. You can read more here
for ([initialization]; [condition]; [final-expression])
statement
EDIT 1:
Though all answers (including mine) mentioned that condition needs to be second statement in the for loop which is correct. There is one more additional important behavior.
The for loop for (let i = 0; i++; i < 10) is actually correct in terms of grammar and even the javascript runtime executes this code.
But, as in your case, if the condition is evaluating to falsy value then it would exit the loop.
Breaking your for loop for (let i = 0; i++; i < 10) into each seperate construct
Initialization: let i = 0; This statement initializes the value of variable i to 0.
Condition: i++; Javascript evaluates the statement to check if the statement is true or not. In case of i++ the runtime firstly checks for the current value of i which is 0 . Since 0 is considered a falsy value the condition evaluates to false and hence the statement is not executed. Also, i++ statement is a post increment which basically increments i and then result the original value of i.
So, if you would have written loop like below, using the intiliaztion of i=1, then it would have worked, though it would be running infinitely untill the browser/Server crashes as the condition i++ would always evaluate to true. I hope that makes sense.
for (let i = 1; i++; i < 10) {
// Statements would run
}
Or
for (let i = 0; ++i; i < 10) { **// Pre increment**
// Statements would run
}
Or
for (let i = 0; i=i+1; i < 10) { **// increment i by assigment
// Statements would run
}
Douglas Crockford in his book Good Parts mention about the usage of ++ & -- and how it can confuse readers.
your for loop syntax is wrong, should be
for (let i = 0; i < 10; i++)
your setInterval code will run every 100 milliseconds for each iteration of the loop (so 10 times every 100 milliseconds)
Nothing to do with setInterval, you simply malformed your for loop:
This:
for (let i = 0; i++; i < 10)
Should be this:
for (let i = 0; i < 10; i++)
First declare the initial state of the loop, then the terminating state of the loop, then the incremental change of the loop.
Observe.

Strange behaviour of for loops

Can anyone tell me why for loop increments even on failed iteration?
for (var n = 0; n <3; n++) {
alert(n); // displays 0 , 1 , 2
}
alert(n); // gives 3
But shouldn't it be like
if(condition):
//desired stuff
increment;
else:
exit;
I seldom use iteration variable mostly I just throw them away upon loop completion but in this case found it to be the cause of a bug
Conceptually n++ is called just after the final statement of the loop body, and the stopping condition is evaluated just before the first statement of the loop body.
So your code is equivalent to
for (var n = 0; n < 3; ) {
alert(n);
n++;
}
Viewed this way, the reason why n is 3 once the loop exists ought to be obvious.
Note that in javascript, n leaks out of the for loop.
for (var n = 0; n <3; n++) {
alert(n);
}
alert(n);
Working of for loop is as follows -
First it initialize the n to 0;
Then it checks the condition whether it is true or not in this case condition is n<3.
Finally it increments the n and again check the condition and if it is true,It again goes in for block. And if the condition is false, It exit the for loop.
In your code when n=3 condition get false. So final value of n is 3.
Just executed the code at chrome console:
It works as expected.
As you have commented that n will be alert with 3, it is wrong, because when n will be 2, condition will be checked i.e. 2<2 will be wrong, then it will be jump from the loop and will alert 2 not 3.

loop flowing steps

This function come from the book "Eloquent Javascript", chapter 3, function.
I don't understand the flowing of the script.
Here is a "for loop" with an impossible mission to make a count value that is equal to 0 and smaller than 0.
At the beginning I expected that it would stop the program but the program is smart. why the impossibility to run the loop doesn't stop the program?
Here is the snippet:
var power = function (base, exponent) {
var result = 1;
for(var count = 0; count < exponent; count ++) {
//repeat as many as needed the self multiplication.
console.log("count = ", count);
result *= base;
console.log(result);
}
return result;
};
console.log("finally we get the number ", power(2, 0));
/* A little question with exponent = 0
Why is that not an error. It is impossible to initiate
with count = 0 && count < exponent.
Weird.*/
The output in repl.it
Native Browser JavaScript
finally we get the number 1
Because count < exponent or rather 0 < 0 is false, so the loop doesn't run and it returns the value of result when it was defined as 1:
var result = 1;
for(var count = 0; false; count ++) {
// This doesn't run
}
return result; // So it's still 1
Thanks to fuyushimoya, I understand:
The first statement in the parenthesis is the initialization of the variable. It is atated anyways before the loop begin. The second statements is a condition, evaluated before the loop is executed, if this statement boolean value is true, the statement inside the loop is executed. after each loop iteration. It change the variable value and then this new value is tested by the second statement and eventually the loop iterates again.
In a case in which the second statement is false at the beginning, the loop doesn't run and the situation is as if we have the first statement alone. See the documentation.

Variable Assignment in basic 1-10 counter

Here is a very basic counter to 10:
for (var i = 1; i <= 10; i++) {
console.log (i); // outputs 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
}
console.log(i);
I would expect the value of i in global space to be 10. It is 11. The only reason I can think of is that it is assigned 11 to break the loop i <= 10.
Is that the correct reason?
Yes, for loops work in this fashion:
for (/*initial conditions set at beginning of loop*/;
/*break condition checked before entering the loop each time*/;
/*command to execute at the end of each loop*/)
{
// stuff to do during loop
}
So your assumption is correct, the for loop runs until i = 11 because that is the first time the loop has reached the break condition.
For loops were created to avoid repetitive while or do/while loops. The above loop can be thought of as:
/*initial conditions set at beginning of loop*/
while (/*break condition checked before entering the loop each time*/){
// stuff to do during loop
/*command to execute at the end of each loop*/
}
A for loop of the form:
for (<inits>; <tests>; <repeats>) {
<body>;
}
is equivalent to:
<inits>;
while (<tests>) {
<body>;
<repeats>;
}
On the last iteration of the loop, i++ will be executed to set i to 11. Then when it returns to the top of the loop, the test i <= 10 will be executed. Since this is false, the loop terminates. At this point, i is still 11.

Javascript indexing array issue

Hi I have an array that hold the following numbers, however when I loop though the eachNode function(which iterates 13 times) it repeats all the list elements 13 times. I tested everything but it still produces an error, I'm I executing the for loop correctly?
list[61,67,78]
var len = list.length;
fd.graph.eachNode(function (node) { // loops thru all node id's in graph (13)
for (var i = 0; i < len; ++i) {
if (i in list) {
var nody = list[i]; // I put the number in a variable
var nodess = fd.graph.getNode(nody); //this takes the number and matches it with a node id, it "odjectify" it
if (node.id != nodess.id) { // if the list nodes are not the same
node.setData('alpha', 0); //
node.eachAdjacency(function (adj) { // this make the unmatched nodes disappear
adj.setData('alpha', 0, 'end');
});
}
}
}
});
This line is unneeded:
if (i in list)
The in keyword returns true if its right operand contains the property specified by its left operand. When using this with arrays, it returns unexpected results. The behavior of this keyword is insignificant in this context, so you should simply take it out.
Moreover, you need to create the list array like this:
var list = [61, 67, 78];
...however, when I loop though eachNode (which iterates 13 times) it repeats all the list elements 13 times
It doesn't, it in fact iterates over eachNode 13 times. You also made a for loop which will traverse the list array by its length.
Now that you've given me more detail as to what you want, here is the updated code. I hope it works for you:
fd.graph.eachNode(function (node) {
var flag = false;
for (var i = 0; i < len; ++i)
{
var nody = list[i];
var nodess = fd.graph.getNode(nody);
if (node.id == nodess.id) {
flag = true; break;
}
}
if (flag)
{
node.setData('alpha', 0);
node.eachAdjacency(function (adj) {
adj.setData('alpha', 0, 'end');
});
}
});
This is the behavior by design:
You loop over the graph (13 times as you say), then inside each iteration you loop over your array (3 items).
If you only want to loop once over your array, just move it out of the outer loop

Categories

Resources