Javascript for loop, index variable in function - javascript

I'm trying to figure out how to generate functions inside for loop.
I have:
for (var i = fir_0_f.length - 1; i >= 0; i--){
var next = i+1;
var N = i;
// Attemps
//goal0_[i](next,N);
//eval('goal0_'+i+'('+next+', '+N+')');
};
Have done also some searching. [] expects a string, eval() is a B.A.D practice. Is there any other way?
How to set the timeout for each function later? So they would run sequentally?
Thanks a lot!

In JavaScript you could use function expressions to build an array of functions:
var goals = [];
goals.push((function (param1, param2) {
// your code for the first function
}));
goals.push((function (param1, param2) {
// your code for the second function
}));
// ... etc
Then in your for loop, you can simply reference your functions as elements of an array:
goals[i](next, N);
UPDATE:
To call your functions with a delay between each other, you'd have to change your loop logic. Instead of using a for loop, call the first function immediately, and then after it runs, make it call the second one using a setTimeout().

for (var i = fir_0_f.length - 1; i >= 0; i--){
var next = i+1;
var N = i;
setTimeout('goal0_'+i+'('+next+','+N+')', 0);
}
Note: errors thrown by goal0_i won't be caught by the loop.
I've noticed this behavior in Firefox.
That means that the following won't work as you expected:
try{
setTimeout(function_throwing_error, 0);
}
catch(e){
alert("I kill you!");
}

For global functions, you can just do:
window['goal0_'+i](next, N);

Related

What is the problem in this loop inside a constructor function? [JS]

I am triying to create a constructor function in order to aferwards be able to instance it to create game boards objects. The program is simple, I just passed the constructor the number of rows and it has to create them.
The for loop is not working and I dont understand the reason, ySize variable is defined. If I remove the for the program works sucessfully and create the section with no problem. Which is the problem with the for loop?
Thank you very much for your time
function AlgorithmType(ySize) {
this.ySize = ySize;
this.createBoard = function() {
let selector; let row
for(let i = 0; i ++; i <= this.ySize) {
debugger; // Debugger is not executed
selector = document.querySelector(".mainContainer")
row = document.createElement("section")
selector.appendChild(row)
}
}
}
let testBoard = new AlgorithmType(5)
testBoard.createBoard() //expected to create 5 rows
Your function rebinds this, which is why this.ySize is not defined. Use an arrow function to access this of the lexical scope (parent scope):
function AlgorithmType(ySize) {
this.ySize = ySize;
this.createBoard = () => {
let selector; let row
for(let i = 0; i <= this.ySize; i++) {
debugger; // Debugger is not executed
selector = document.querySelector(".mainContainer")
row = document.createElement("section")
selector.appendChild(row)
}
}
}
Side note: As #atomNULL pointed out, your for-loop syntax is incorrect as well. See his answer
Your for loop syntax is wrong, the correct syntax would be:
for (let i = 0; i <= this.ySize; i++)
Also you should use an arrow function to access this instead of rebinding it current way.

Add delay between script execution, especially in FOR loop

I have a block of script that will produce a set of DOM. It has a loop that contains an asynchronous function (function A) and then function B after it. Function B's effect will be shown if the asynchronous function (A) is completely executed. I tried to use setTimeout function, but it doesn't work well, some of object outside setTimeout could not be accessed inside it.
Here's the script:
var parents = data.hasil.parent.split(">>");
var jmlparent = parents.length;
for (var i = jmlparent-2; i >= 1; i--){
add_parent(); // it's the asynchronous function (function A)
setTimeout(function (){
$("#parent_"+(jmlparent-i)).val(parents[(i-1)]); //(function B)
//returns error: parents is not defined
},200);
//i think 200ms is enough for browser to complete the execution of function A
}
Does anyone have the solution?
Function A should return a promise which when resolved you would call function B. You do not know how long function will take to resolve, therefore setTimeout() is not a good approach.
You also do need a closure:
var parents = data.hasil.parent.split(">>");
var jmlparent = parents.length;
for (var i = jmlparent-2; i >= 1; i--){
(function( i ) {
add_parent().done(function() {
$("#parent_"+(jmlparent-i)).val(parents[(i-1)]);
});
})( i );
}
I did not want to discuss the use of setTimeout but just improve you code. Try this :
...
for (var i = jmlparent-2; i >= 1; i--){
add_parent();
setTimeout(function (a){
$("#parent_"+(jmlparent-a)).val(parents[(a-1)]); //(function B)
},200, i); // we pass here the i var to setTiemout
}
About add_parent() why you call it inside the loop ? may be before the loop once is better ?! I dont know ...

example needed of callback function inside for loop in javascript

I'm looking for something simple and straight forward, most of what I've pulled up on stack isn't quite what I need. I have an array that I want to loop through while calling a function after each iteration. What would that look like?
I'm assuming you're having problems with this because of the way closures are handled in Javascript. Douglas Crockford talks about this, in his book, by using the example of a function that assigns a click event handler to an array of nodes. The "intuitive" way is:
var addHandlers=function(nodes){
var i;
for(i=0; i<nodes.length;++i){
nodes[i].onClick= function {
alert (i);
};
}
};
However, this is not correct: each onClick callback will show the same value of i = nodes.length-1. This is because the value of i is not copied, but referenced in each inner function. The better way would be to create a helper function that returns a callback, something along the lines of the following:
var addHandlers = function (nodes) {
var helper = function (i){
return function (e){
alert (i);
}
}
for (int i =0; i<nodes.length();i++){
nodes [i].onClick=helper (i);
}
}
Plus, this allows you to avoid creating a function at each iteration.
var arr = [1,2,3];
for(var i = 0; i < arr.length; i++){
someFunction();
}
If you want to process one elment of the array to be used in an asynchronous funcion and then process the next next element you can do something like this;
function asynchCallback(arrayToProcess,someVar){
console.log("callback called with parameter:",someVar);
processArray(arrayToProcess);
}
function processArray(arr){
if(arr.length===0){
console.log("done");
return;
}
var someVar=tmp.splice(0,1);
setTimeout(function(){
asynchCallback(tmp,someVar[0]);
},100);
}
//send a copy of the array:
processArray([1,2,3].concat());

Why is this javascript not running as expected?

function animateGraph() {
var graph;
for(i=0; i<10; i++)
{
var start = new Date();
while((new Date()) - start <= 500) {/*wait*/}
document.getElementById("timeMark").innerHTML = phoneX[i].epoch;
}
}
The loop works. The wait works. But the document.getElement is not showing up until the last item in the array...why?
Using setTimeout will allow the code to run and not lock up the page. This will allow it to run the code and will not effect other elements on the page.
var cnt = 0;
(function animateGraph() {
document.getElementById("timeMark").innerHTML = phoneX[cnt].epoch;
cnt++;
if (cnt<10){
window.setTimeout(animateGraph,500);
}
})();
The while loop, waiting for a datetime, is not a good way to wait - it just blocks execution. It keeps the browser (including UI, and its updating) frozen until the script finishes. After that, the window is repainted according to the DOM.
Use window.setTimeout() instead:
function animateGraph(phoneX) {
var el = document.getElementById("timeMark")
var i = 0;
(function nextStep() {
if (i < phoneX.length )
el.innerHTML = phoneX[i].epoch;
i++;
if (i < phoneX.length )
window.setTimeout(nextStep, 500);
})();
}
Please note that this runs asynchronous, i.e. the function animateGraph will return before all phoneXes are shown.
Use setTimeout instead of a while loop.
https://developer.mozilla.org/en/DOM/window.setTimeout
Also try something like this.
Javascript setTimeout function
The following snippet uses a helper function to create the timers. This helper function accepts a loop counter argument i and calls itself at the end of the timer handler for the next iteration.
function animateGraph() {
var graph;
setTimeMarkDelayed(0);
function setTimeMarkDelayed(i) {
setTimeout(function() {
document.getElementById("timeMark").innerHTML = phoneX[i].epoch;
if (i < 10) {
setTimeMarkDelayed(++i);
}
}, 3000);
}
}
You actually need some sort of helper function, otherwise you'll end up overwriting the value of i in your for loop in every iteration and by the time your timers run out, i will already be 9 and all handlers will act on the last element in phoneX. By passing i as an argument to the helper function, the value is stored in the local scope of that function and won't get overwritten.
Or you could use setInterval like Radu suggested, both approaches will work.

Javascript scope and calling a function

My code:
for (var i = 0; i < mapInfos.length; i++) {
var x = function () { doStuff(i); };
google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x);
}
The doStuff method simply alerts the value of i. mapInfos has two entries, so you'd expect it to alert 0 and 1, but instead it alerts 2 and 2. I can appreciate vaguely why it is doing this (although var i should keep it local to the scope of the loop?) but how can I make it work as intended?
edit — note that when first posted, the original question included a link to a jsfiddle that seemed to be a relevant example of what the current question is trying to achieve, only it appears to work ...
The code in the jsfiddle works because there's only one "i" in that code. The "i" used in the second loop (where the functions are actually called) is the same "i" as used in the first loop. Thus, you get the right answer because that second loop is running "i" through all the values from zero through four again. If you added:
i = 100;
functions[0]();
you'd get 100 printed out.
The only way to introduce a new scope in JavaScript is a function. One approach is to write a separate "function maker" function:
function makeCallback(param) {
return function() {
doStuff(param);
};
}
Then in your loop:
for (var i = 0; i < mapInfos.length; i++) {
var x = makeCallback(i);
google.maps.event.addListenerOnce(mapInfos[i].map, 'titlesloaded', x);
}
That'll work because the call to the "makeCallback" function isolates a copy of the value of "i" into a new, unique instance of "param" in the closure returned.
Create a new scope for it.
Functions create scope.
function doStuffFactory(i) {
return function () { doStuff(i); };
}
for (var i = 0; i < mapInfos.length; i++) {
var x = doStuffFactory(i);
google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x);
}
Change it to
var x = function (param) { doStuff(param); };
Obviously what is going on is that you are alerting a variable that is changing. With the above change it copies it so even if i changes it will still alert the right value.
Javascript doesn't have block scope, so you don't get an x that's local to the loop. Yea!
It has function scope, though.
Yep, weird isn't it!Pointy has an explanation
I have no idea why your first example worked (I wasn't expecting it to) Pointy has an explanation of why your first example worked - The reason why your second one doesn't is because i is scoped to the function containing the for loop, not to the scope defined by the for loop. In fact the only things that have scope in JavaScript are functions. This means that by the time your function gets executed i is 2.
What you need to do is create a scope, for example:
for (var i = 0; i < mapInfos.length; i++) {
var x = (function() {
return function () { doStuff(i); };
})(i);
google.maps.event.addListenerOnce(mapInfos[i].map, 'tilesloaded', x);
}
See JavaScript closures in for-loops for more.

Categories