I'm sure there's a really simple solution to this but I can't wrap my head around it. I'm trying to create and array of objects within a for loop like so:
for(var i = 0; i < 100; i++) {
foos[i] = new Foo(i*10);
bars[i] = someObject.createBar({
x : 0,
y : 0,
foobar = function() {
foo[i].a = true;
}
});
}
When trying to run this I get 'cannot set property a of undefined', both foos and bars are declared earlier in the code as globals.
It works fine if I create foos as foos[0] and access through bars[0]. I suspect it's something to do with function level scoping but as far as i can see the arrays should be accessible on the global object....
You need to "anchor" the value of i. To do this...
for(var i=0; i<100; i++) {
(function(i) {
// now do stuff with i
})(i);
}
Try this:
for(var i = 0; i < 100; i++) {
foos.push( new Foo(i*10) );
bars.push( someObject.createBar({
x : 0,
y : 0,
foobar = function() {
foo[i].a = true;
}
}) );
}
You cannot set value "a" of undefined, because "foo[i]" is undefined. You never defined foo[i]. Did you mean foos[i], maybe?
Also, as others have said, your function foobar is going to use the same value of i for every object you create. You should create a new closure with i, which will allow you to define a local variable i that can be different for each interior function, as so:
for(var i=0; i<100; i++) {
(function(i) {
// now do stuff with i
})(i);
}
The value of i in the execution of foobar is the one at the end of your loop (100). Because the loop block is a closure.
You'd better store the value you want. For example :
for(var i = 0; i < 100; i++) {
foos[i] = new Foo(i*10);
bars[i] = someObject.createBar({
x : 0,
y : 0,
i : i,
foobar: function() {
foos[i].a = true;
}
});
}
Or use a intermediate closure in your loop to enclose i :
for(var i = 0; i < 100; i++) {
(function(i){
foos[i] = new Foo(i*10);
bars[i] = someObject.createBar({
x : 0,
y : 0,
foobar: function() {
foos[i].a = true;
}
});
})(i);
}
The first solution is more explicit, the second one is maybe now more usual.
Related
Can someone please explain why does it console log out 10, 10, 10 instead of 9, 9, 9?
When it goes through for loop shouldn't it stop at 9?
var foo = [];
for (var i = 0; i < 10; i++) {
foo[i] = function() {
return i;
};
};
console.log(foo[0]());
console.log(foo[1]());
console.log(foo[2]());
Whenever any function which is using any variable from parent scope is executed, it gets that value of a variable which it is holding at the time of function execution. In your case i is already reached to 10 at the time of execution because of i++.
For getting expected result, you can add IIFE to it, which will hold the value of i in its scope.
var foo = [];
for (var i = 0; i < 10; i++) {
foo[i] = (function(i) {
return function() {
return i;
};
})(i);
};
console.log(foo[0]());
console.log(foo[1]());
console.log(foo[2]());
You can use this syntax which keeps the context
for (let i = 0; i < 10; i++) {
foo[i] = () => i;
};
console.log(foo[0]());
console.log(foo[1]());
console.log(foo[2]());
https://jsfiddle.net/bandpay/8zat3bnn/
if i have something like these
var executed = false;
var executed2 = false;
var executed3 = false;
How should i put this in a for loop?
You could make executed a single array rather than a series of variables.
In that case, you could write:
var executed = [];
for(var i = 0; i < 3; i++) {
executed.push(false);
}
Then, to access the values, you can use:
executed[0] === false // ==> true
executed[1] === false // ==> true
executed[2] === false // ==> true
Use Array of Objects instead of using variables in a loop
var executed = [];
for (var i = 0; i < 3; i++) {
executed.push({
status: false
});
}
console.log(executed);
You can declare global variables, use window[]
for(var i = 1; i <= 3; i++) {
window['executed' + ( i > 1 ? i : '' )] = false;
}
// now you can access 'executed', 'executed2', 'executed3' globally
but, DO NOT use global variables if you can.
javascript:
for (i = 0; i < n; i++)
{
v = fn(obj);
}
function fn(o)
{
for(i = 0; i < o.length; i++)
{
...
}
}
The first index get modify from second FOR inside the function fn(o);
How is it possible? what's the scope of index?
It doesn't look like you're declaring i as a local variable, so what's happening is that i being treated as a global variable. You need to write the var keyword in order for a variable to become a local variable.
for (var i = 0; i < n; i++)
{
v = fn(obj);
}
function fn(o)
{
for(var i = 0; i < o.length; i++)
{
}
}
I don't see any var so it looks like you're not varing anything, but I'll add those in and answer the question
Is it possible to modify the i in one for loop from another in a different scope?
When using functions in JavaScript, all primitive arguments are passed ByVal and all object arguments are passed ByRef. This also happens when using =.
Therefore, if you want to modify i out-of-scope, you will need to always access it through an Object.
function foo() { // scope this away from fn
for (var c = {i: 0}; c.i < n; c.i++) { // i wrapped in object
v = fn(obj, c); // pass wrapping object into `fn`, too. Now see `fn`
// c.i is now the result of change in `fn`
}
}
function fn(o, c) {
for(var i = 0; i < o.length; i++) {
// ...
}
// make change to c.i
c.i = 0;
}
foo();
I am pushing some functions into an array but I am not sure how to run the functions as I loop through the array.
I am trying to get red yellow green to output to the console.
Here is a fiddle to my JavaScript: http://jsfiddle.net/rYNv4/
Here is the code that I have so far as well:
var myArr = [];
myArr.push( logItRunner('red') );
myArr.push( logItRunner('yellow') );
myArr.push( logItRunner('green') );
console.log(myArr);
//Function to be stored in array. Should return the logIt function.
function logItRunner( arg ) {
return function() {
logIt( arg );
};
}
//Function to log a string to the console
function logIt (color) {
console.log(color);
};
//Function to loop through array and fire functions within the array
function runIt () {
for (var i = 0, len = myArr.length; i < len; i++) {
//Fire Function within Array at position i and log the argument to the console.
myArr[i];
};
};
runIt();
myArr[i] is a function reference. You call the function it refers to just like you do any other time you have a function reference, with ():
In your loop, change:
myArr[i];
to
myArr[i]();
See how I'm executing the myArri; below.
You've almost got it, you just forgot the ().
//Function to loop through array and fire functions within the array
function runIt () {
for (var i = 0, len = myArr.length; i < len; i++) {
//Fire Function within Array at position i and log the argument to the console.
myArr[i]();
};
};
It is all about how JavaScript closures work, this usually is the way we teach JavaScript closures, so your sample is a good one, since it clarifies the concept.
This is the way I usually do the exact same thing to teach JavaScript closures, which is completely similar to yours with some little differences:
var myArr = [];
myArr.push('red');
myArr.push('yellow');
myArr.push('green');
var funcArr=[];
function pushIt () {
for (var i = 0, len = myArr.length; i < len; i++) {
var func = (function(color){
return (function(){
console.log(color);
});
})(myArr[i]);
funcArr.push(func);
};
};
function runIt () {
for (var i = 0, len = funcArr.length; i < len; i++) {
funcArr[i]();
};
};
pushIt();
runIt();
This question already has answers here:
JavaScript for loop index strangeness [duplicate]
(3 answers)
Closed 9 years ago.
Take a look at this code:
var arr = new Array();
for (var i = 0; i < 10; i++) {
arr[i] = {
func:function() {
console.log(i);
}
}
}
arr[0].func();
I am confused by this, because I thought this would work. I basically would like each object in the array to print the value it was given when the function was created.
Right now when I call func(), it prints 10 in the console. Is there a way to make it print 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 instead? Thanks!
The problem is that the function inside is referencing the variable 'i' which increases every time. You can store the value of 'i' in each iteration in the object alongside the function like this:
http://jsfiddle.net/Sgnvp/
var arr = new Array();
for (var i = 0; i < 10; i++) {
arr[i] = {
func:function() {
console.log(this.value);
},
value: i
}
}
arr[0].func();
You have to create a closure to encapsulate the value. Here I'm calling consoleIt and passing it i. consoleIt creates a closure around the i
var arr = [];
function consoleIt (i) {
return function () {
console.log(i);
}
};
for (var i = 0; i < 10; i++) {
arr[i] = {
func: consoleIt(i)
};
}
arr[0].func();
This is no better really than the way that thebreiflabb did it, but it's an interesting technique that's worth knowing:
var arr = [];
for (var i = 0; i < 10; i++){
(function(i){
arr[i] = {
func : function(){
console.log(i);
}
};
})(i);
}
arr[0].func();
It just uses an anonymous closure to scope i.