This question already has answers here:
JavaScript variables declare outside or inside loop?
(12 answers)
Closed 5 years ago.
what's the difference between the following two sections of code?
one.
var arr = [70,80,150,310,260,100,78];
var pointArr=[];
var point={};
for (var i = 0; i < arr.length; i++) {
point.x=i*80;
point.y=(arr[i]/600)*240;
pointArr.push(point);
console.log(point);
console.log(pointArr);
}
two
var arr = [70,80,150,310,260,100,78];
var pointArr=[];
for (var i = 0; i < arr.length; i++) {
//diff
var point={};
point.x=i*80;
point.y=(arr[i]/600)*240;
pointArr.push(point);
console.log(point);
console.log(pointArr);
}
results:
one
enter image description here
two
enter image description here
For code one, point is initialised once. Whereas for code two, it is initialised for every loop.
when you initialize the variable inside the loop, it will initialize (reset) with each iteration. This means that you will push data to an empty object and log that object every time the for loop runs, instead of continuously pushing to the object that was created outside the loop in your first example. Does that make sense?
In JavaScript Objects are passed by reference. Whereas primitive types are passed by value and are immutable.
So in your first code example the variable point will be stored in memory as a reference in form of a pointer. Inside the loop you keep pushing the same reference to pointArr. Changing the x and y property of point will just change the referenced value. This has nothing to do with the loop itself.
Just change your first example to the following:
var arr = [70,80,150,310,260,100,78];
var pointArr=[];
var point={};
for (var i = 0; i < arr.length; i++) {
point.x=i*80;
point.y=(arr[i]/600)*240;
pointArr.push(point);
}
window.setTimeout(function() {
point.x = 'foo';
point.y = 'bar';
console.log(pointArr);
}, 2000)
By looking at the console output you can tell that you have several occurrences of the same reference inside pointArr.
By re-declaring point inside your loop, like you did in the second example, you simply created a new reference for each point.
You may want to take a look at the following link which explains this in more detail.
Primitive Types and Reference Types
Hope that helps.
Related
I've searched about call by reference on javascript but still am confused.
consider this code.
let arr = [];
let temparr = [2,3,4];
arr = temparr;
temparr.push(5);
console.log(arr); //[2,3,4,5]
console.log(temparr); //[2,3,4,5]
let arr2 = [];
let temparr2 = [2,3,4];
arr2 = temparr2;
temparr2 = [1,2];
console.log(arr2); //[2,3,4]
console.log(temparr2); /[1,2]
For the first case, arr gets affected by temparr due to arr = temparr, however, in the second example, arr2 does not get affected by modification in temparr2. My question is,
In the first example, Why in the first place is arr getting affected by the modification of temparr? Is this in the line of call by reference? If so, on what occasions does it trigger such operation?
In the second example, the only difference is that i did not use push but assign new array to modify the temparr2. However this time arr2 did not get affected. What is the difference with the first example?
Thank you very much
Your question has less to do with how arguments are passed (everything is passed by Value all the time in JavaScript, by the way) and more to do with how Objects are stored.
In your first example, the line most relevant to your question is this:
arr = temparr;
Here, you are setting up a second variable to hold the same value as the first, but Object variables don't hold the Object, they hold the location in memory to where the object is stored. So, after that line, you have two variables that both point to the same, one underlying object. If either one of them modifies that underlying object, the other will see the same thing because they both point to only one object.
In your second example, you start out in a similar way with:
arr2 = temparr2;
Which, again, sets you up to have two variables that point to the same one, underlying object. But, then you do this:
temparr2 = [1,2];
Which doesn't modify the one underlying object, it simply reassigns the second variable to a different object, and now the two variables don't point to the same thing anymore.
It's really no different than saying:
x = 7;
and then saying:
x = 8;
The old value in x goes away and there's an entirely new value stored.
If you wanted to modify the underlying array, you would do that via the Array API, for example:
temparr2.splice(2,1); // Delete one item at index position 2
This is why the array was modified when you used .push() in the first example - - you were working on the object, not reassigning the variable.
This Javascript function inside my class doesn't seem to modify the array that it's passed to it by reference:
this.filterEqualCities(this.birthCitiesNames, this.birthCitiesPositions);
filterEqualCities: function(citiesNames, citiesPos) {
var tempNamesArray = [];
var tempPosArray = [];
for(var i=0; i<citiesNames.length; i++) {
var name = citiesNames[i];
name = name.split(',')[0];
if(tempNamesArray.indexOf(name) == -1) {
tempNamesArray.push(name);
tempPosArray.push(citiesPos[i]);
}
}
citiesNames = [];
citiesPos = [];
for(var i=0; i<tempNamesArray.length; i++) {
citiesNames.push(tempNamesArray[i]);
citiesPos.push(tempPosArray[i]);
}
}
When you do:
citiesNames = [];
citiesPos = [];
the variables are no longer references to the original arrays that were passed in, now they're references to these two empty arrays.
If you want to clear out the original arrays, you can simply set their lengths:
citiesNames.length = 0;
citiesPos.length = 0;
To expand a bit upon #Barmar's excellent answer - the issue is that arrays and other objects are not really "passed by reference" in Javascript, even though it seems that way a lot of the time, and it's often described that way. They're passed by value, like all other variables - but that "value" is itself a "reference" to an actual value stored in memory, not to another variable itself.
So if you were to modify citiesNames, say by pushing a new element onto it, that would be reflected outside the function - because you'd be modifying that shared value to which both citiesNames variables (local and global) are references to.
But when you do citiesNames=[], you're taking the citiesNames local variable and reassigning it to a completely new value, and there's no way your other citiesNames variable can know about that.
This behaviour isn't unique to Javascript. Python certainly behaves the same way (and perhaps others too that I'm not as familiar with).
This question already has answers here:
Copy array by value
(39 answers)
Closed 4 years ago.
I found a really weird (for me) problem
I have this global variable ARRAY
var A = [1,2,3,4]
then inside a function, I made local var and assign previous global var to it
function someFunc() {
var X = A;
}
I then made another local Var and assign it with the first local var's value
var Y = X;
I then push a new value to Y
Y.push(6);
but the, the new value (6) didn't only pushed to Y, but also to the 2 original array (X and A). What happened? Doesn't it supposed to only change Y?
Please help, thank you.
Here is my full code:
var A = [1,2,3,4];
function someFunc(){
var X = A;
var Y = X;
Y.push(6);
console.log(A);
console.log(X);
console.log(Y);
}
$("#test").click(function(){
someFunc();
});
as you can see, it is triggered by clicking on element with id #test.
All three console.log, even thought represent different variable, it return the same result, ARRAY with 6 on it
Edit. Yes there is a similar question to this, but even though the problem is similar and the solution is identical, but the initial understanding is what different. In my question, I initially asked "Why", because I am not aware of those variable actually 'refer' to same array instead of 'assigning', so I have no idea if I should search for how to assign instead of refer, since I assumed that using = means assigning, sorry
What happens is that you do not copy the array you just reference it. You can use the method slice to create a copy of it:
var X = A.slice();
Do mind that you can use this approach only with primitive values. Check this if you need to deal with objects How do you clone an Array of Objects in Javascript?
Your arrays aren't cloned: assigning a variable does not clone the underlying object.
You can shallow-clone an array using the slice method:
var cloned = original.slice();
But array and object items within the array are not cloned using this method. Numbers and strings are cloned, however, so this should work fine for your case.
An array in JavaScript is also an object and variables only hold a reference to an object, not the object itself. Thus both variables have a reference to the same object.
I've never seen this happen before, and can't find anything about this on the internet. I'm not even really sure how to ask this question.
I can't seem to reproduce this at will, but it is consistent once it starts happening.
When i try to access an element of an array with a variable, such as an iterator, the array is seeing the iterator variable as undefined, because it thinks i'm asking for a member of the array.
so for example:
for(var x = 0; x < width; ++x)
{
if(something != somethingelse)
{
var element = array[x]; // exception
}
}
this for example may cause an exception because x is undefined. So in firefoxes debugger, i check the value of the "x" inside [x], it is undefined. i check the value of "x" in the for loop line, it is a correct integer. So i put a watch on the x inside [x] and find that i'm watching "array.x".
I've been using javascript for years, but i haven't seen this happen before. I don't usually debug with firefox though, so is this an issue with firefox?
i guess my question is, is there anything obvious that i may be doing wrong by accessing an array using a variable?
I forgot to mention, i do have a fix, but it's not something i would like to always do when this happens. right before i access the element inside the array, i set the array member variable to the variable i'm using as an index.
for example:
for(var x = 0; x < width; ++x)
{
if(something != somethingelse)
{
array.x = x;
var element = array[x]; // exception
}
}
I have the following code.When I access w[1][0], I want only the object at that one location to be changed. However, all the objects change instead. I'm assuming this is because at some level, they are all pointing to the same object. How would I fix this?
var createArray = function(dim,init){//takes an array of dimensions and the initial value of each element
if(dim.length > 0){
var x = new Array();
for(var i = 0; i < dim[0]; i++)
x[i] = createArray(dim.slice(1),init)
return x;
}
return init;
}
var w = createArray([2,2],{top: false,left: false});
console.log(w);
w[1][0].left = true;
console.log(w);
In JavaScript, objects are passed by a reference, not by value. That means that if you pass the same object to a few variables, they all point to the same place in memory. This is why your init object is being changed everywhere.
To prevent this, you need to clone the object before assigning it to your variables. One of the simplest built-in methods is to use JSON, like this:
var copy = JSON.parse(JSON.stringify(original));
So in your case that would be it:
x[i] = createArray(dim.slice(1), JSON.parse(JSON.stringify(init)));
w[1][0].left = true;
This line is changing the only instance of the object. See, this line:
var w = createArray([2,2],{top: false,left: false});
is the only line in your code that creates a new object (of the type you're interested in) via the {} literal there. All other set operations (newVar = init) only copy a reference to that same object.
That sounds annoying, but it has a lot of good uses in code. To fix it, you'll want to create a copy each time, to replace the final line of createArray
var myCopy = {};
for (var key in origObject) {
if (origObject.hasOwnProperty(key)) {
myCopy[key] = origObject[key];
}
}
return myCopy;
Be warned - this is a "shallow copy", so it will only copy the top-level properties, and any objects a level deep will still be references. Many JavaScript libraries have functions to create deep copies for you.