for-loop not modifying a global variable? [duplicate] - javascript

This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 6 years ago.
I wrote a for-loop that for some reason refuses to modify a global variable. Instead, it seems to create a local variable that it modifies temporarily. A condensed version of my code is as follows.
var clubsArray = [obj, obj, obj];
//each obj contains a property of "goalsFor" which holds an integer
var madridTotalGoals = 0;
var barcaTotalGoals = 0;
function findTotalGoals(clubsArray, totalGoals) {
for(var i = 0; i < clubsArray.length; i++) {
totalGoals += clubsArray[i].goalsFor;
}
}
findTotalGoals(clubsArray, barcaTotalGoals);
// this loops properly and does the math, but it never changes the value of barcaTotalGoals
In the full code there are numerous arrays that hold "club" objects; each contain a property key "goalsFor", which hold an integer as a value. There are also numerous "totalGoals" variables (two are specified here) that have been declared globally.
Does anyone know why the global variable (e.g. barcaTotalGoals) is not being modified when passed through this function? When I console log each step of this loop, the math is taking place but the result is not being stored. I apologize if this has been asked before but I've searched thoroughly.

The variable you are trying to pass, is passed by value and not reference. So it wont affect the original variable
You can assign the value once the for loop is finished
function findTotalGoals(clubsArray, totalGoals) {
for(var i = 0; i < clubsArray.length; i++) {
totalGoals += clubsArray[i].goalsFor;
}
barcaTotalGoals = totalGoals;
}

You are passing by value instead of by reference...
Instead, you could try like this:
clubsArray = [obj, obj, obj];
var totalGoals = {
madrid: 0,
barca: 0
}
function goalsByCountry(clubsArray, totalGoalsClub) {
for(var i = 0; i < clubsArray.length; i++) {
totalGoals[totalGoalsClub] += clubsArray[i].goalsFor;
}
}
goalsByTeam(clubsArray, 'barca');

Related

How to understand 'let' in 'for' statement? [duplicate]

This question already has answers here:
What is the difference between "let" and "var"?
(39 answers)
let keyword in the for loop
(3 answers)
Closed 5 years ago.
As far as I know, 'let' is used for declaring block variable. But it can't declare twice with same name. For example:
'use strict';
let a = 1;
let a = 2; // syntax error
So how to separate each scope in 'for' iteration with the same variable name?
'use strict';
for(let i = 0; i < 3; i++){
setTimeout(function(){
console.log(i);
});
}
// output:
// 0
// 1
// 2
Dose interpreter change the variable name silently? Any info will be appreciated.
I don't think is a duplicated question. Because I really want to ask is the conflict between two theory.
let scopes your variable to the block it's in.
After you've assigned a scope to a, you can't overwrite it. So the second time you use let, it can't handle that.
Correct usage would be:
'use strict';
let a = 1;
a = 2;
In the for loop , i is declaring at the beginning only and in each iteration it change the value of it .
let is used to variable that you will write there value again .
In the first example you define variable with name 'a' so you cant define another with same name , but you can change it value , which happened in the for loop.
'use strict';
let a = 1;
let a = 2; // syntax error
'use strict';
let a = 1;
var a = 2; this will overwrite...
here you specified a value already.. your intention is , it shouldn't change in runtime. so you cant able to change it once declared in block with same type let ..
that why you getting this error..
intention of let is value should not change..
in loop ,
it will be separate on iterate.. so it print value on runtime. so it wont overwrite it...
let allows to create the variable once, but the value of the variable can be changed,
example -
let t =5//
let t = 6 // throws an errow but
t =7
console.log(t) - gives 7
In the loop the variable is not declared again but only its value is incremented.
It is similar to the following:
'use strict';
let i = 0;
i = i + 1;
consider the code being iterated again and again until the condition fails.
for(let i = 0; i < 3; i++){
// code
}
step:
let i = 0
checkout i<3
exec code
i++, equals i = i + 1 // not occur error, while let i = i + 1 will occur exception
loop step-2 until i<3 == false
In your first example the variable a is defined twice in the same scope. This gives you an error because the variable already exists. let doesn't allow this, redeclaring with var does. This is one advantage of using let.
var a = 3;
var a = 2;
console.log(a); // 2
let b = 3;
let b = 2; //syntax error
let c = 3;
var c = 2; //also a syntax error
In a for loop, the i variable has a different scope. Meaning these two i variables here aren't the same.
let i = "my string";
console.log(i); //my string
for(let i = 1; i <= 3; ++i){
console.log(i); //1, 2, 3
}
console.log(i); //my string
The javascript runtime doesn't care if your variable is named the same. It will differentiate the scope and thus the reference to the variable. It's replacing your reference to i whichs value is 4 to the new variable in the for loop.
I have an answer on here on Stackoverflow which describes how the Android compiler doesn't care about your variable names. It's the same here, the runtime uses different "names" (different memory addresses).

Javascript global variable getting set to a new value [duplicate]

This question already has answers here:
Change the value of an array changes original array JavaScript
(3 answers)
Closed 7 years ago.
I'm new to javascript and coding in general, and I could use some help.
I am setting a global variable (generatedNumbers) equal to another variable (numbers) so that I can do some validation on the array. However, when I change the value of numbers, my global variable generatedNumbers gets changed as well. Any help would be appreciated.
var generatedNumbers;
function generateNumbers(numberOfNumbers) {
'use strict';
var i;
generatedNumbers = [];
for (i = 0; i < numberOfNumbers; i = i + 1) {
generatedNumbers.push(generateRandomNumber(9).toString());
}
}
function checkEachValidNumberUsed(userExpression, numbers) {
'use strict';
var i, j;
for (i = 0; i < userExpression.length; i = i + 1) {
for (j = 0; j < numbers.length; j = j + 1) {
if (userExpression[i] === numbers[j]) {
numbers.splice(j, 1);
window.console.log(generatedNumbers);
}
}
}
if (numbers.length !== 0) {
return true;
}
}
function validateExpression(userExpression) {
'use strict';
var numbers, validUserInput;
numbers = generatedNumbers;
window.console.log(generatedNumbers);
if (checkEachValidNumberUsed(userExpression, numbers)) {
document.getElementById("feedbackText").innerHTML = "Each number must be used exactly once.";
} else {
return true;
}
Arrays (and all other non-primitive types) are pass-by-reference, not copied, when you use the assignment operator = or pass them to a function, so any changes made to numbers (or the values of the elements of numbers) will be reflected in generatedNumbers.
For your array here, numbers = generatedNumbers.slice(0); will sufficiently clone the array, but keep in mind that if the contents of the array is not a primitive type (e.g. any object that you use the new keyword to create) will not be cloned: both arrays will reference the same objects.
That's because they both refer to the same object. If you want to make a copy of generatedNumbers (which I think you want to do in validateExpression) use slice.
numbers = generatedNumbers.slice(0);
In Javascript if you have an array
var a = [1,2,3,4];
and assign a to another variable
var b = a;
the two are referring the very same array object... for example after
b.push(99);
a will also see the mutated array.
If you want to make a copy you need to do so explicitly for example with
var b = a.slice();

Passing a global array to a function overwrites array [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 7 years ago.
I'm trying to pass a global defined array as an argument to a function.
I thougt this function would treat the argument as a local variable.
But it doesn't... Changing the (in my opinion) local variable also changes the values of the global array. What am I doing wrong?
clickX = [];
for(var i=0; i<10; i++) {
clickX[i] = i;
}
doThis(clickX);
function doThis(x) {
for(var i=0; i<x.length; i++) {
x[i]++;
alert(clickX[i]); // this alerts the changed value of x[i] and not the origin value of the global array
}
}
jsfiddle:
https://jsfiddle.net/n546rq89/
In Javascript, arrays are passed by reference by default. You can alternatively pass ARRAY.slice() to pass by value:
clickX = [];
for(var i=0; i<10; i++) {
clickX[i] = i;
}
doThis(clickX.slice());
function doThis(x) {
for(var i=0; i<x.length; i++) {
x[i]++;
alert(clickX[i]); // this alerts the changed value of x[i] and not the origin value of the global array
}
}
Look at this thread for an explanation of slice() and copying array in JS.

Why is result different (using var vs. let)?

This uses var
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 10
This uses let
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 6
I don't understand why the result is different. Can somebody guide me?
The resulting array consists of functions, each function body looks like this:
console.log(i);
The value of i depends on whether we used var or let to declare the variable.
var (ECMAScript 5 and 6)
Here i is a global variable whose value is 10 after exiting the loop. This is the value that is logged.
let (ECMAScript 6)
Here i is a local variable whose scope is restricted to the for statement. Moreover, this variable gets a fresh binding on each iteration. This is best explained by your code transpiled to ECMAScript 5:
"use strict";
var a = [];
var _loop = function(i) {
a[i] = function() {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
a[6](); // 6
So, on seventh iteration for example, the value of i will be 6 (counting from zero). The function created inside the iteration will refer to this value.
I think it would be much better to not define functions in a loop, you could easily accomplish this with one function definition that returns a closure:
function logNumber(num) {
return function() {
console.log(num);
}
}
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = logNumber(i);
}
a[6]();
Regarding the difference between the two examples, one is using let for block scoping. A better example that shows the difference would be:
ECMA5:
for (var i = 0; i < 10; i++) { }
console.log(i); // 10
ECMA6:
for (let i = 0; i < 10; i++) { }
console.log(i); // i is not defined
Edit: as I stated in my comment to your question, this is more likely a side-effect of the transpiler you are using. Firefox supports block scoping and both versions of your loop produce 10 as output (which they should).
This is correct behavior according to the spec. The behavior with var and let is defined to be different.
See the spec, at https://people.mozilla.org/~jorendorff/es6-draft.html#sec-forbodyevaluation. According to this, the relevant concepts, which make the function declared inside the loop close over the current value of the block-scoped loop index, are things called "per-iteration bindings" and "per-iteration environment".
Babel handles it correctly, producing the following code:
var a = [];
var _loop = function (i) {
a[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
This implements the semantics of for (let by isolating the contents of the for loop into a separate function parameterized by the index. By virtue of doing that, the function no longer closes over the for loop index, and i is treated separately in each function created. Thus the answer is 6.
Traceur does not produce the correct result. It yields 10.
So the famous question that has been asked 100 times on SO, about why my function declared in a loop and closing over the index index is using the "wrong" value of the loop index, shall be asked no more?
The issue is a bit more nuanced that merely proclaiming that "of course, let is block-scoped". We know that. We get how it works in an if block, for example. But what's going on here is a bit of an twist on block scoping in the context of a for, hitherto unknown to many people including me. It's a variable actually declared outside the "block" (if you think of the block as the body of the for statement) but has a separate existence inside each iteration of the loop.
For more, see https://github.com/babel/babel/issues/1078.
Why is result different in ES6 and ES5?
Because let and var are different. let is block-scoped while var is function-scoped.
In your first example there is only a single variable i. Every function you create has a reference to the same variable i. At the moment you call a[6](), i has the value 10, because that was the termination condition for the loop.
In the second example, every iteration of the loop has it's own variable i. It works exactly like in other languages with block scope.

Can I create dynamic object names in JavaScript? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
javascript - dynamic variables
Dynamic Javascript variable names
I need to create a number of objects on a page and want to name them sequentially. Is there a way to do this in JavaScript?
for (i=0;i<num;i++){
var obj+i = new myObject("param1","param2");
obj+i.someProperty = value;
}
This way I can dynamically create a varying number of objects (dependent on the value "num") and then set their properties appropriately.
I can do this in PHP, is there a way to do it in JavaScript?
This isn't recommended, but does what you're trying to do (if you're running in a browser and not some other js environment).
for (i = 0; i < num; i++) {
window['obj' + i] = new myObject("param1","param2");
window['obj' + i].someProperty = value;
}
obj0.someProperty;
This works because global variables are actually properties of the window object (if you're running in the browser). You can access properties of an object using either dot notation (myObject.prop) or bracket notation (myObject['prop']). By assigning window['obj' + i], you're creating a global variable named 'obj' + i.
The better option is to use an array or parent object to store your objects.
myObjs = {};
for (i = 0; i < num; i++) {
myObjs['obj' + i] = new myObject("param1","param2");
myObjs['obj' + i].someProperty = value;
}
myObjs.obj0.someProperty;
Or use an array like lots of other answers suggest.
That's what arrays are for, to hold a collection of something:
var objs = [];
for (i=0;i<num;i++){
objs[i] = new myObject("param1","param2");
objs[i].someProperty = value;
}
Dynamic variables are almost always a bad idea.
You can create, and you can set/modify properties of that object.
Modified code:
var obj = {}; //
for (i=0;i<num;i++){
obj[i] = new myObject("param1","param2");
obj[i].someProperty = value;
}
I recommend you to use array. as
var obj = []; //
for (i=0;i<num;i++){
obj[i] = new myObject("param1","param2");
obj[i].someProperty = value;
}

Categories