I'm having trouble understanding how scoping works in JS, my background is in R and Python.
This is a toy example. The games_array always prints out as empty at the end. And the array variable doesn't seem to be present in the console.
for(var row_i = 0; row_i < 50; row_i++){
var games_array = [];
if(row_i % 2 == 0){
console.log(data[row_i].name);
games_array.push(data[row_i].name);
}
}
console.log(games_array);
But then this works:
var games_array = [];
for(var row_i = 0; row_i < 50; row_i++){
if(row_i % 2 == 0){
console.log(data[row_i].name);
games_array.push(data[row_i].name);
}
}
console.log(games_array);
I don't understand why I can't create an empty array and use it within a for loop.
I need to wrap this inside an outer loop and use the games_array in the outerloop.
Any help is appreciated.
The problem is not with scoping. After all, since you declared the variable using var instead of let, the scope extends outside of the for loop. The problem is that each time the loop runs, it sets games_array to [], which means the array gets cleared each time the loop runs.
In the second example, you only initialize the array once, which is why it works.
Related
This question already has answers here:
Why variable hoisting after return works on some browsers, and some not?
(5 answers)
Closed 5 years ago.
I am currently using a for loop in javascript to iterate over an array.
Its working fine, but I can still get the variable value used in for loop outside the loop. I am not able to find the cause.
Here is the code snippet.
var list = ['delhi','mumbai','pune','kolkata'];
for (let i = 0, max = list.length ; i < max ; i++ ){
var current_city = list[i];
//other code goes here
}
console.log(current_city);
It's printing 'kolkata' outside the for loop.
You just need to set var current_city to let current_city . . .
var list = ['delhi','mumbai','pune','kolkata'];
for (let i = 0, max = list.length ; i < max ; i++ ){
let current_city = list[i];
//other code goes here
}
console.log(current_city); // shows error, as you expect.
That behavior is correct. You keep reassigning the value of current_city so it just logs the last one. If you want them all logged, just move the console.log inside the loop.
var list = ['delhi','mumbai','pune','kolkata'];
for (let i = 0, max = list.length ; i < max ; i++ ){
var current_city = list[i];
console.log(current_city);
}
JavaScript doesn't have block scope, just function scope. Since the initialization of current_city is within one function, that variable is accessible anywhere else in that same function. These variables are not local to the loop, i.e. they are in the same scope the for loop is in.
You keep reassigning the value of current_city so it is assigned the last item from the array when the loop ends. Hence you get the result kolkata
The process: In the game I'm making, there's a for loop that's supposed to save a value in an array. That value changes with each iteration. The problem: when the loop is done running, every element of the array is identical, all showing the most recent value.
I know this issue is common, and I've made so many different tweaks and attempts at solving it over the past 2 days.
0) I tried separating things into separate functions as much as possible.
1) I tried defining my loop counters with "let" so they would have a local scope.
2) I tried wrapping my assignment in a self-executing function so it would happen immediately, preserving the value of currentlyOn before the next loop iteration changes it. My counter is the variable c.
(function(c2, currentlyOn2) {
onAtSameTime[c2] = currentlyOn2;
return 0;
})(c, currentlyOn);
3) I tried attempt #2 with the added feature of returning a function, which still didn't save the value of currentlyOn. This option isn't a good one for me anyway, because the whole point is that I'm doing some computations ahead of time so my game will have a quick animation loop.
onAtSameTime[c] = (function(currentlyOn2) {
return function() {
return currentlyOn2;
};
})(currentlyOn);
I'm tired of beating my head against this wall. Can anyone explain what I'm doing wrong?
For more details, check out the jsfiddle I made. The problem area is at line 59, using a simple assignment:
onAtSameTime[c] = currentlyOn;
onAtSameTime[c] = currentlyOn; sets onAtSameTime[c] equal to the reference of currentlyOn, since currentlyOn is an array, not a primitive value. That reference gets updated with each iteration. You could work around that by creating a copy of the array before adding it to the onAtSameTime array. Something like onAtSameTime[c] = [].concat(currentlyOn); would do the trick.
See this fork of your JSFiddle: https://jsfiddle.net/L2by787y/
You could make a copy from currentlyOn for assigning to onAtSameTime[c]. This keeps the values, but does not keep the reference to the same array.
onAtSameTime[c] = currentlyOn.slice(); // use copy
"use strict";
function log(text) {
document.getElementById("logbox").innerHTML += JSON.stringify(text) + "<br>";
return 0;
}
function whichSwitchesAreOn() {
var currentlyOn = [],
flickedSet,
flickedOne,
turningOnCheck;
for (var c = 0; c < switchesToggled.length; c++) {
flickedSet = switchesToggled[c];
for (var d = 0; d < flickedSet.length; d++) {
flickedOne = flickedSet[d];
turningOnCheck = currentlyOn.indexOf(flickedOne);
if (turningOnCheck == -1) {
currentlyOn.push(flickedOne);
} else {
currentlyOn.splice(turningOnCheck, 1);
}
}
log("currentlyOn: " + currentlyOn);
onAtSameTime[c] = currentlyOn.slice(); // use copy
}
return 0;
}
var switchesToggled = [[0], [1, 2], [0], [2], []],
onAtSameTime = [];
whichSwitchesAreOn();
log(onAtSameTime);
<div id="logbox"></div>
You say you have tried let?
Did you have let currentlyOn = [] inside of the for loop?
for(var c = 0; c < switchesToggled.length; c++) {
let currentlyOn = [];
I'm having troubles gathering information about clicked eventListeners.
I have this loop which builds an array:
myButtonList = document.getElementsByTagName('a');
myAnchorList = [];
for (i=0; i < myButtonList.length;i++) {
if (myButtonList[i].getAttribute('class') == 'flagged') {
myAnchorList.push(myButtonList[i]);
}
}
For each <a> put into myAnchorList array, I also create another array storing other informations from the same tag (classe and other atrributes).
Here's where I'm struggling. I'm trying to set up an eventListener to send me back those information when those <a> are being clicked. But somehow, the fact that I create a function (for the eventListener) within a loop breaks everything.
for (i=0; i < myAnchorList.length; i++) {
myAnchorList[i].addEventListener("click", function(i){
console.log(alpha+' - '+beta[i]+" - "+charlie[i]);
});
}
My values will either be undefined or some other values which will be the same for each buttons I clicked. alpha is working well as it doesn't depend on any iteration of the loop, but not the others.
Can anybody see what I'm doing wrong here?
for (var i = 0; i < myAnchorList.length; i++) {
(function (i) { //Passes i to your function
myAnchorList[i].addEventListener("click", function () {
console.log(alpha+' - '+beta[i]+" - "+charlie[i]);
});
})(i);
}
The variable "i" in closure that you created in the loop will always retrieve the last value(myAnchorList.length - 1). You shouldn't create closure in a loop, and you can use a "factory" method to create closure instead.
Why doesen't prompt() inside a for loop in javascript work for my code below?
var P = [];
for(i=0;i++;i<10)
{
var g=parseInt(prompt("What is the money you paid in"+i+ "month?"));
P[i]=g;
}
Your for loop is wrong. It should be
for (i=0;i<10;i++)
You mixed up the second and third parts. The condition comes second, the variable increment comes last.
You swapped the parts of the for loop. The condition is second:
for(var i = 0; i < 10; i++) {
Also don't forget var, and parseInt(x, 10) prevents some weird behaviour.
Your loop is formatted incorrectly, a for loop should be:
for ( state; condition; action )
So, given your case, the correct loop is:
for (var i = 0; i < 10; i++)
for some sick reason, my check productIDs[addIndex] = allProductIDs[lastProductFoundIndex + i]; causes my app to spin into an infinite loop:
numberOfImagesToDisplay is set to 4
if (state == "next")
{
for(var a = 0; a < numberOfImagesToDisplay; a++) {
alert("a=" + a + ", numImages=" + numberOfImagesToDisplay)
if (a > 0) { addIndex = productIDs.length + 1; }
alert("I'm in GetNextProductIDs() 1");
//var lastProductFoundIndex = $.inArray(lastProductID, allProductIDs);
//alert("I'm in GetNextProductIDs() 2");
if (lastProductIndex >= 0) {
alert("I'm in GetNextProductIDs() 3");
//productIDs[addIndex] = allProductIDs[lastProductFoundIndex + i];
}
}
}
If I take out that line, it moves on.
Update: Resolved. lastProductIndex was not defined. So what was happening is that it would get there and the loop would end but it's weird because a callback was being called again when it should have ended. So that callback method kept calling this method and this method would end at that spot, the callback method would again be called, and so you had an endless loop.
That's very strange. All I can think is that you have an onpropertychange event firing that also modifies i. Major longshot, I know.
What if you add the var keyword to your for loop? That would turn it into a local variable instead of a global variable so no other function could inadvertantly trash your loop index.
for (var i = 0; i < numberOfImagesToDisplay; i++)
Note: You should have the var there whether or not that's the problem.
Update: What does alert("i="+i+", numImages="+numberOfImagesToDisplay) display each iteration through your loop? Do those variables have the expected values?
Are you sure this loop is stuck? Maybe it's another loop. Could it be that you're re-entering this loop repeatedly thereby getting repeated alerts? I just don't see how that line could cause this loop to become an infinite loop.
I don't see you incrementing variable a in there anywhere, but you're incrementing a variable i in your loop. a will therefore always be 0 -
for(var a = 0; a < numberOfImagesToDisplay; i++)
It's not related to your suspected problem line, but, at the line
for(var a = 0; a < numberOfImagesToDisplay; i++)
your setting a = 0 and the loop will run while a < numberOfImagesToDisplay. I dont see anywhere where you are incrementing or changing a to exit the for loop.