Infinite loop due to missing let statement and call by reference

Hello,

I am not very good in JavaScript however I am running into a problem by calling a function where the parameters handed over to the function are treated as call by reference instead of call by value. I understood from the documentation that let is not available and var should be used instead. However, how do I get a call by value then?
Here is a simple code to explain the behaviour:

function calculate(start,amountHours)
{
  console.log("calculate Average for "+amountHours+" hours starting wiht hour: "+start); 
  var average=0;
  var j=start;
  for(i=0;i<amountHours;i++)
  {
    average=average+j*2;    
    j++;
  }
  average=average/amountHours;
  return average;  
}

for(i=0;i<10;i++)
{
  console.log("i before call: "+i);
  var aver=calculate(i,4);
  console.log("i after call: "+i+" plus average: "+aver); 
}

The output on the console is the following:

i before call: 0
calculate Average for 4 hours starting wiht hour: 0
i after call: 4 plus average: 3
i before call: 5
calculate Average for 4 hours starting wiht hour: 5
i after call: 4 plus average: 13

as i is handed over to the function as a starting point and is treated by a call by reference, i is always 4 after the function call. I want just a call by value, so that i is after the first call still 0 and after the second one 1 and so on. With this behaviour I end up in a infinite loop as i is always 4 and will never reach 10.

What am I doing wrong here? In a normal Javascript environment I declare j in the function with let and it works as expected.

  • Platform information:
    • Hardware:Rasperry PI
    • OS: Linux
    • Java Runtime Environment: Java17
    • openHAB version:4.3.0

You can use let and const inside the function. The prohibition on let and const only applies to the main context of the rule and relates to how the rules are cached and run. The function has its own context that is separate from the main context and is treated as normal so let and const work inside the function.

For this very reason, it’s good practice to declare the iteration variable in the for initialization. This is the standard way to avoid this issue:

for (var i = 0; i < 10; i++)

and

for (var i = 0; i < amountHours; i++)

See more here:

You can, of course, also work around these issues by using more complete variable naming in the loops. Instead of repeating i as the loop variable use something iLoop for the main for structure and iAver for the for structure in the function.

1 Like

Thanks for pointing it out. I did misunderstood the documentation though. After changing it, it works as expected.

For those are interested in the solution. Here is the modified code:

function calculate(start,amountHours)
{
  console.log("calculate Average for "+amountHours+" hours starting wiht hour: "+start); 
  let average=0;
  let j;
  j=start;
  for(var innerI=0;innerI<amountHours;innerI++)
  {
    average=average+j*2;    
    j++;
  }
  average=average/amountHours;
  return average;  
}


for(var i=0;i<10;i++)
{
  console.log("i before call: "+i);
  let aver=calculate(i,4);
  console.log("i after call: "+i+" plus average: "+aver); 
}

If is good practice to use let in the for loops too.

for(let i=0;i<10;i++)

That too is inside its own context and therefore not subject to the global context restriction on using let and const. That alone probably would have solved the original problem.

You can also use the same approach shown in most of the JS transformation examples with a self executing function. That takes pretty much the entire code out of the global context, and then you can freely use let and const.

(function() {
    // your code goes here
})()