Suppose you have the following code:
var array = [1];
var array2 = array;
array2.push(2);
alert(array);
This will alert "1,2", even though I clearly declared array as [1], and then did no changes to it. It's like array and array2 gets connected, and every change I do to array2 affects array. I simply want to declare array2 with the same value as array, not connect them.
Why does this happen and how to prevent it?
Thanks in advance!
jsFiddle
The problem is, that array2 is pointing on array.
what you want is:
var array2 = array.slice(0);
This really creates a copy of "array" and does not let the variable array2 point on "array".
It's because arrays and objects in JS are "passed by reference" (actually a copy of reference), not value (as it happens with primitives). There are many ways to do it, one of them being concatting an empty array:
var array = [1];
var array2 = array.concat([]);
array2.push(2);
alert(array); // 1
alert(array2); // 1,2
See some nice answers here: Does Javascript pass by reference?
Befor all , in Javascript an array is an Object
so the array variable is pointing to an in array (that you created [1]) that has an adresse in the memory (for example #1234abc). So the variable array it self is a pointer that points to an array.
You did var array2 = array
so array2 will point to the same adress in the memory (to the same object).
In other words, array2 is array they are pointing to the same object.
To get what you want, you have to create a new array and assign the same values of array1, this is called cloning.
You can do it with this trick var array2 = array.slice(0);
array2 is a reference to the original array, so if you modify it, the original will change too.
You´ll have to set array2's value to array.slice(), which clones the original and gives you a new reference.
It is because of concept Pass by reference. Internally both the variables are pointing to same memory location. So, when you change one variable that will effect other variables as well. Try slice() method if you intend to copy only values but not reference as it is. :)
Related
Ok I am brand new with javascript and for some reason these arrays are exactly the same but I only edit one, any ideas?
let array = ["one", "two", "three", "four"]
let newArray = array
newArray.forEach((element,i) => {
newArray[i] = element+"_done"
})
console.log(array)
console.log(newArray)
Any ideas, this is my first question, so please don't be to harsh I am still learning.
Don't worry this is quite a simple fix. Basically when you did
let array = ["one", "two", "three", "four"]
let newArray = array
You didn't create a new array you just created another pointer to the existing array. Its a very simple fix. Don't worry I had this exact same problem when I started in javascript. Just use the spread syntax this is quite a good read for some more info on it. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax and also research object and array destructuring, as it will be very useful. Fireship io did a very good tutorial on this. His videos are all ways good to watch and they are very well made. https://www.youtube.com/watch?v=UgEaJBz3bjY
Anyway here is the fix:
let array = ["one", "two", "three", "four"]
let newArray = [...array]
newArray.forEach((element,i) => {
newArray[i] = element+"_done"
})
console.log(array)
console.log(newArray)
This case is also known as call by reference. Arrays in JavaScript are reference type. when you wrote the line:
newArray = array
so instead of assigning the value of array to newArray, you passed the reference of array to newArray, which means any action performed on newArray will automatically be applied to array. to solve this you might use this expression:
newArray = [...array]
This is known as breaking the reference.
Array in Javascript is reference type. So when you do newArray = array, you are just creating a new variable named newArray in stack which is pointing to the same memory location of values (in heap) of array variable. Hence modifying one modifies the other.
Object, Array are reference type and number string, boolean are value type.
This is a classic example the old problem of "call by reference" and "call by value" if you want to understand these concepts better I would advise to google it.
But in a nutshell when you say let newArray = array it does not create a new copy of the array but instead newArray is a reference to array. If you change the one you change the other.
Here are some ways to properly copy a object https://www.javascripttutorial.net/object/3-ways-to-copy-objects-in-javascript/
This is because both the variables point to same array. Instead of copying the array, the reference to the original array is assigned when using '=' operator.
To copy the elements of existing array to new array, ES6 spread operator is very helpful.
Check this indepth article on JavaScript Arrays. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
var array1 = [1,2,3,4,5,6];
var array2 = array1; // assigns reference to array1
var array3 = array2; // assigns reference to array1
var copy = [...array1]; //new array is created and elements of array1 are copied to this new array.
array1.push(7); //every reference to this array will get updated.
console.log(array1); // [1,2,3,4,5,6,7];
console.log(array2); // [1,2,3,4,5,6,7];
console.log(array3); // [1,2,3,4,5,6,7];
console.log(copy); // [1,2,3,4,5,6]; //Doesn't get modified as it is copy.
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.
I wanted to know how javascript arrays work internally, I mean when for example you create a new array.
array = [1,2,3];
It's internally creating a new array: array = new Array();
and then calling Array.push() or similar?
Thanks.
The best resource to find out how javascript internals work is ECMAScript specification itself.
In order to understand what happens internally when you do array = [1, 2, 3] you would need to read section 7.3.16 CreateArrayFromList (elements). Roughly what happens is that first Array object gets created, then each element gets set to this object with CreateDataProperty (7.3.4 CreateDataProperty section) (DefineOwnProperty) internal method.
Then you want to learn what exactly happens when you push element to array. You check 22.1.3.17 Array.prototype.push ( ...items ) section for this. There you will find out that it uses quite different algorithm, namely it sets specific property of an object (7.3.3 Set (O, P, V, Throw) section).
So the answer is no, creating array like a = [1, 2, 3] does not uses same mechanics to insert items as push does. The first one roughly creates new property on (newly created) array object, the push sets property to existing object.
and then calling Array.push() or similar?
No. As you can see in the below example that when array is initialized push (overridden) method is not invoked.
Array.prototype.push = function(){ console.log("adding") };
var array = [1,2,3];
//console.log(array);
But, it is invoked when console statement is executed (after un-commenting the same).
var array = [1,2,3];
It doesn't call push but it's a simpler way to initialize an array when you know the elements in advance.
If you want to add another element you can do it in multiple ways like:
1) array.push(22); // adds integer 22 to the array
or
2) array[4] = 22; // adds integer 22 to the array at index 4
You can even do this:
array[20] = 22; // this will resize the array and keep all the uninitialized elements returns undefined. So array[10] is undefined, for ex.
If you want to know all the details about arrays explained in a simple way I recommend you the book: Secrets of the JavaScript Ninja. It has an entire chapter about arrays.
https://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/1617292850/ref=sr_1_1?ie=UTF8&qid=1519484868&sr=8-1&keywords=javascript+ninja
var arrN = [1, 2, 3];
function init(arr){
arr = [];
console.log(arrN) //output [1, 2, 3], expect []
}
init(arrN);
When using splice or push methods the array passed to a function is being modified. So I am trying to understand what is happening when using assignment operator, why it's not changing the array? is it creating the local var of the passed array?
Any help will be appreciated!
You need to distinguish between the variable and the actual object (the array). splice and push are changing the object.
arr = [] is just changing the variable, the old object just stays as it is.
There is a difference in assigning a different object to a variable or mutating the object currently referenced by a variable.
(Re)assigning
When you do an assignment like:
arr = []; // or any other value
... then the value that arr previously had is not altered. It is just that arr detaches from that previous value and references a new value instead. The original value (if it is an object) lives on, but arr no longer has access to it.
Side note: if no other variable references the previous value any more, the garbage collector will at some point in time free the memory used by it. But this is not your case, since the global variable arrN still references the original value.
Mutating
It is another thing if you don't assign a value to arr, but apply instead a mutation to it, for instance with splice, push, pop, or an assignment to one of its properties, like arr[0] = 1 or arr[1]++. In those cases, arr keeps referencing the same object, and the changes are made to the object it references, which is visible to any other variable that references the same object, like arrN.
Clearing an array
Now if you want to clear the array that is passed to your function, you must avoid to make an assignment like arr = .... Instead, use methods that mutate the array in place:
arr.splice(0)
Or, alternatively:
arr.length = 0;
Now you have actually mutated the array, which is also the array referenced by arrN.
In JavaScript, particularly when working with objects the assignment operator (=) has three jobs.
Assignment
Creating a new reference if the right side is an object.
Breaking any previous referencing and creating multiple assignments if both sides are objects.
Such as;
var a = [1,2,3], // a is assigned an array
b = a; // b is assigned just a reference to a
a = ["a","b","c"]; // b to a referral is now broken
// a is assigned with ["a","b","c"]
// b is assigned with [1,2,3]
same would apply if it was done in reverse order;
var a = [1,2,3], // a is assigned an array
b = a; // b is assigned just a reference to a
b = ["a","b","c"]; // b to a referral is now broken
// b is assigned with ["a","b","c"]
// a keeps it's existing assignment as [1,2,3]
Your are passing arrN to the console instead of passing arr. Also, you just call a function by its name, not by the keyword function. Here is the corrected code:
var arrN = [1, 2, 3];
function init(arr){
arr = [];
console.log(arr)
}
init(arr);
You have also declared init() with an argument arr, which is not needed in this case. What ever the value you pass to init(), the value of arr will be [] because you are reassigning it in the function.
By js convention and as far as I know
Primitive datatypes are worked under pass by value and
complex datatypes are worked under pass by reference
If it so
var ary = [1,2,3];
var dupAry = ary;
//Now I am going to rewrite the ary variable as follows
ary = [3,4,5];
Now I log the values of ary and dupAry it logs different values. By its standard both array should return the vaues.
so why it return different array values?
Another scenario
var ary = [1,2,3];
var dupAry = ary;
//No I gonna apply splice method to the ary.
ary.splice(0,1);
Now both array return same values and it works fine with its standard.
Finally why its doesn't applied with first scenario?
var dupAry = ary;
This assigns a reference to the array that ary points to to dupAry. Both ary and dupAry now hold a reference which points to the same array object. If you now assign something else to ary, then dupAry will continue to hold a reference which points to the array object, and ary will now hold some other value.
By assigning something to a variable, you're not modifying the object that variable already holds; you're modifying the object reference that variable holds.
ary.splice(0,1)
This modifies the actual object that both variables points to, so both see the change.
When you do this:
ary = [3,4,5];
... you aren't altering an array: you are destroying the previous reference and creating a brand new variable* with a brand new array. See the difference with:
ary.push(99);
(*) Well, not really a new variable, of course—I didn't know how to word it.