In JavaScript, how do I mutate the value of an array inside of a function? I know that happens when using certain array methods, but it doesn't seem to work for normal assignment.
var arr = [4]
function changeArray(arr) {
arr = [1,2,3];
}
// arr is still equal to [4]. I want it to equal [1,2,3].
It's my understanding that this code doesn't change the value of "arr" outside of the function. How can I do it in a way that mutates the array that was passed as an argument?
You can use .splice:
arr.splice(0, arr.length, 1, 2, 3);
Or you can empty the array and .push the values:
arr.length = 0;
arr.push(1, 2, 3);
// or given an array of values
arr.push.apply(arr, newValues);
However, make sure it is clear that the function changes the array in place. While there are native functions that does this (like Array#sort), I'd argue that this is not as common as simply returning a new array.
It's my understanding that this code doesn't change the value of "arr" outside of the function.
Correct. Assigning a new value to a variable or property never changes the value of another variable or property (exceptions: global scope and with statements).
You basically tried to change the value of a variable, not mutate the value itself.
JavaScript is call/pass/assign by value (Wikipedia also mentions "by sharing"), not by reference.
Related
This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 10 months ago.
Is it possible in Javascript to pass an array (from outer scope) to a function, and mutate the original array?
I've read several answers mentioning that f()'s arr argument is actually a copy, it's name just shadows the outer scope variable. Other mention arrays are always passed by reference, but are 'copied' (that is a confusing explanation).
But if that is the case, why does arr[0] = 'a'; find the arr reference in outer scope? But arr = ['a', 'b'] does not?
If arr = ['a', 'b'] was declared in the function with a blockscoped var type (let, const), that would make more sense..
let a = [0,0,1,1,1,2,2,3,3,4];
function f(arr, z) {
arr[0] = 'a';
arr = ['a', 'b']
}
f(a);
console.log(a);
[ 'a', 0, 1, 1, 1, 2, 2, 3, 3, 4 ]
From within f() function, the line arr[0] = 'a' modifies arr in the outer scope
But the reference arr =(without aletorconst`) should also refer to outer scope?
First thing is arrays are always passed as reference in javascript.
Now coming to your question, when an array is passed to a function the argument variable of that function will hold that reference, in your case it's arr argument. If you mutate arr it will mutate original array as it is referring to original array but if you just assign some other value or reference to arr it will no longer hold reference to that original array and any changes to new reference won't have any effect on that array.
JavaScript is pass by value. However, when passing an object as a parameter, the value is the reference.
An array is an object. When modifying the property of an object, the change will be reflected even outside of the function scope. Thus, modifying one item (e.g, a property of the array) produces said effect. However, replacing the object will only replace the value to which said reference points toward, thus the change will only be reflected within the scope of the function.
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 read before that the only way to change the value a variable holds is using an assignment operator (=, +=, ..)
But in this example from mdn, nums variable returns two different values by changing one of the arrays used in the assignment without using an assignment operator.
var num1 = [[1]];
var num2 = [2, [3]];
var nums = num1.concat(num2);
console.log(nums);
num1[0].push(4);
console.log(nums);
However, when I remove the nested array and just push 4 to num2 array directly, the printed value doesn't change.
Check this example
The concat function returns a new array, comprised of the elements of both arrays.
In the first case, the num1 array and nums contains references to the same inner array, so when you change it, it is reflected in both.
In the second case, the arrays contain numbers, and there is nothing shared between the arrays. That's why when you push to one, the other doesn't change.
As for the assignment confusion, nums always points to the same array until you assign a new value to nums. That doesn't mean you can't change the contents of the array itself.
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.
I am passing an array of objects to a function whose role is to remove some of those objects according to some sort of criterium.
The problem is that the scope isn't being handled the way I would like it to be, and the original array is not being updated.
In that function, the return value is already used and may not be changed. How might I be able to change the array?
A variable pointing to an array is a reference to it. When you pass an array, you're copying this reference. So you should just modify the array parameter and it will modify the original array.
var a=[1,2,3];
var c=f(a);
alert(a); // a is now [1,2,3,6]
function f(b) {
b.push(6);
return 1;
}