This question already has answers here:
JavaScript by reference vs. by value [duplicate]
(4 answers)
Closed 6 years ago.
I want to use = to initiate an array in a function. However, = cannot change the array, but push can.
I want it equals to ["a", "b"]. But now the result is ["1", "2"].
I tried arr = ['a', 'b']; and also arr = ['a', 'b'].slice();. But neither works.
How can I let = work in this case?
var array = [];
init(array);
console.log(array);
function init(arr) {
arr.push('1');
arr.push('2');
arr = ['a', 'b'];
}
https://jsbin.com/kiveyu/4/edit?js,console
So the reason this happens is because you are assigning the local variable the new array, whereas prior to the assignment, the local variable held the value of the passed in array.
The parameter holds a reference to the value passed in. However, the parameter is still a local variable. Writing to that variable will only modify the local variable, and will lose the reference held.
To expand, from being called:
init(array);//call function init with value array
Next the context environment is created upon instantiation, it holds a local variable array, and the value of that variable is the same as the value of the passed in array (in your example they have the same name)
function init(array) {
After this, two values are pushed to the value of array, which is the value of the passed in array.
array.push('1');
array.push('2');
Here is where it seemed the confusion took place. The local variable array (still holding the value of the passed in array) has its value changed to a new array. The result is that the local variable array no longer holds the value of the passed in array, but now holds the value of ['a','b'].
array = ['a', 'b'];
That is why it looks like you cannot change the array by assignment - because the only thing you have access to in that scope is the local variable with regards to the original array.
function init(array) {
array.push('a');
array.push('b');
}
Related
This question already has answers here:
Copy array by value
(39 answers)
Copy array of objects and make changes without modifying original array
(5 answers)
Closed 10 months ago.
I was studying JS when faced an unexpected behavior by me. It's probably something related to local vs global scope, however I could not find the answer. Here how it goes:
I have two arrays, one empty and another with some values. If a push the one with values inside the empty one, then updating the values using .push() method, it will update the array inside the other as well:
let newArr = [];
let valueArr = [0,0];
newArr.push(valueArr);
// newArr = [[0,0]]
console.log(newArr);
valueArr.push(0);
// newArr = [0,0,0] --> updates it
console.log(valueArr);
However, if a now try to update the variable using = assignment, it won't change the array inside newArr
let newArr = [];
let valueArr = [0,0];
newArr.push(valueArr);
// newArr = [[0,0]]
console.log(newArr);
valueArr = [0,0,0];
// newArr = [[0,0]] --> does not update it
console.log(newArr);
Does anyone know why pushing has this behavior and reassigning does not? It's due local/global scope or when I reassign the valueArr variable, the newArr variable loses its track?
This is not related to local/global scope.
TLDR
When you call push on an array, you add items to the existing array. When you use an assignment, you create a new array that has nothing to do with the one that was stored in the variable previously.
Detailed
Here's what's happening in the code:
Step 1. let valueArr = [0,0];
When you assign an array to a variable, there are two things happening:
An array is getting created and saved in memory([0,0])
The valueArr variable saves a reference to the created array
Step 2. newArr.push(valueArr);
Then, you push valueArr array into the newArr array. Now newArr[0] contains an element with the same reference as valueArr. They both point to the [0,0] array.
Step 3. valueArr.push(0);
In this step, we push an element to the array that valueArr references. Since newArr references the same array, newArr[0] gets updated too.
Step 4. valueArr = [0,0,0];
Here we repeat step 1. Create a new array and save its reference to the valueArr. The thing is that we change the reference stored in the valueArr, but newArr[0] still points to the old array. This is why you don't see any updates: it's a completely different array.
This would be a good start if you want to learn more about reference types: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0
TLDR
If you want to update newArr, do so explicitly:
valueArr = [0,0,0];
newArr[0] = valueArr;
In depth explanation
You need to distinguish between an object and a reference to object. An object is a "thing". But a reference to an object is just a way to describe which "thing" you are talking about.
A variable is a way to explicitly reference an object using a name. But you can also reference objects in other ways, such as (as you discovered) through an array index.
A couple of important things to keep clear:
The assignment(=) operator explicitly creates a reference to an object. You can later refer to that object through the variable name.
A variable can refer to different objects over time (through repeated applications of the assignment operator).
Arrays are JavaScript objects. You create a new array object every time you use square brackets ([ ]) on the right hand side of the assignment operator.
a.push(b) implicitly creates a reference from some index of a to the object being referenced by b at that point in time.
You can use the strict equality(===) operator to determine whether two expressions refer to the same object.
/*
We create a new array, lets call it Object 1.
We can refer to that array using the variable name `a`.
*/
let a = [];
/*
We create a new array, lets call it Object 2.
We refer to that array using the variable name `b`.
*/
let b = [0];
/*
When we call `push` we are implicitly creating a
new reference: from a[0] to Object 2.
*/
a.push(b);
/*
`a[0]` and `b` are both referring to
the *exact same* object: Object 2.
*/
console.log("Are `a[0]` and `b` the same object:", a[0] === b); // -> true
/*
We create a new array, lets call it Object 3.
We explicitly tell Javascript to use `b` to
refer to Object 3 from this point forward.
*/
b = [2];
/*
Notice that `a[0]` still refers to Object 2.
*/
console.log("Are `a[0]` and `b` the same object:", a[0] === b); // -> false
/*
We can explicitly tell javascript to update `a` by
using the assignment operator.
*/
a[0] = b;
console.log("Are `a[0]` and `b` the same object:", a[0] === b); // -> true
This question already has answers here:
Pass variables by reference in JavaScript
(16 answers)
Closed 1 year ago.
My problem can be reduced to this trivial (or so it seemed) bit of code
var myArray = [1,2];
function addOnetoArrayElement(element){
element +=1;
console.log(element); // Returns 3
}
addOnetoArrayElement(myArray[1]);
console.log(myArray[1]); // Returns 2
I find in fascinating that one can do all sorts of operations on arrays like map, reduce, push to an array but no reference at all to doing simple arithmetic operations of elements of an array. Never mind all that stuff about hoisting,scope, passing by value and reference. I'm sure that maybe someday I'll know enough to contribute to that discourse. What must I do to make myArray[1] = 3?
You assume that myArray[1] will be passed to the function in a way that it can modify that element in myArray (so-called by reference).
But myArray[1] is just a number, it's a primitive type and is passed by value. It means a copy is passed to the function which has no connection to myArray. As a result modification of element param does not change myArray (see docs).
Primitive parameters (such as a number) are passed to functions by value; the value is passed to the function, but if the function changes the value of the parameter, this change is not reflected globally or in the calling function.
For reference there are just 7 primitive data types in JS: string, number, bigint, boolean, undefined, symbol, and null.
To fix the issue we need to pass whole myArray to function as first parameter (by reference because it's an Array) and index as second. In this case myArray will be passed by reference and the function will be able to modify it.
var myArray = [1,2];
function addOnetoArrayElement(arr, ind){
arr[ind] += 1;
console.log(arr[ind]); // Returns 3
}
addOnetoArrayElement(myArray, 1);
console.log(myArray[1]); // Returns 3
I don't understand why assigning the array to a new value doesn't affect the new array.
I know that "push" modifies the original array, splice also, and filter or slice doesn't, this is not my question. my question is that why assigning doesn't.
i have looked through old questions answers saying it is passed by reference but again if it is passed by reference then changing it's value should affect the reference also.
const modify = (someArray) => {
// modified my array
someArray.push(1)
// modified my original array
someArray[0] = 'A'
// didn't modify my array and I want to know why.
someArray = ['whatever']
}
let myArray = ['a', 'b']
modify(myArray)
console.log(myArray) // ["A", "b", 1]
In Javascript (and Java or C#) everything is by default passed by value!
The important is to know, what the value is. This line let myArray = ['a', 'b'] creates new array in memory and put the reference to it into myArray. Now, the value of myArray is the reference to the memory where ['a', 'b'] reside.
When you pass it to modify function, the value - which is the reference - is copied from myArray to someArray. It means someArray can access the same memory segment of the same array, therefore change the values inside that array, but you cannot change the value of myArray (which is the reference to that array) from someArray.
As I've described this to beginners many times, I've found that it's best to think of Objects in Javascript as being passed and assigned as a pointer (as in the way pointers work in C/C++). So, when you do this:
let a = [1,2,3];
let b = a;
You now have two variables that each have a pointer to the same [1,2,3] array. I find it works best to think about the array existing on its own and you now have two variables that each point at that array. When you assign b = a, it doesn't make a copy of the data, it just points b at the same data that a was pointing at.
If you modify that array with something like a.push(4) or assigning like a[0] = 9, then the one and only one array that both a and b point to has been modified. So, whether you access that array from a or from b, you will see the change because both variables point at the same physical array object.
But, if you reassign some other array to b like this:
b = [9,8,7];
You've just taken a new array and put a pointer to it in b. The other variable a still points to the same original array that is used to. It hasn't been changed in any way.
When you pass an array as an argument like you are doing in your modify() function, the function argument in the function is just like the b variable in the above example. It's just another variable that points at the same array. If you modify the array itself, then both variables will point at the same modified array. But, if you reassign the argument variable to now point at some other array, only that variable is affected.
['a', 'b'] is an array. myArray is a variable that refers to that array. someArray is a variable local to modify function that will take the value of myArray (i.e. the reference to your array; so both myArray and someArray refer to the same array). As you noted, someArray.push(1) and someArray[0] = 'A' both modify the array referred to by someArray. someArray = ["whatever"] will change the reference of someArray to the new array ['whatever'], but myArray still refers to the old array. At the end of the function, someArray variable disappears (and ['whatever'] is forgotten, since nothing refers to it any more).
There is no way in JavaScript to change the reference of the variable passed into a function (as e.g. C++ can); you can only manipulate what received reference points to.
I am novice to JavaScript but I know JavaScript does calls by value when passing primitives and calls by reference when passing objects.
var a = [4,5];
var temp = a;
console.log(a); // [4,5] OK
console.log(temp); // [4,5] OK
temp = temp.push(6); // Insert one more element into temp array
console.log(a); // [4,5,6] why so??
Console.log(temp); // [4,5,6]
I know this is because of reference got change . What should I do to avoid deep copy ?
If I change temp don’t want to change original reference a, it should print [4,5].
If you want to copy it, you can use slice:
var temp = a.slice(0);
Edit: thanks to cuberto for pointing me out slice(0)
"I know JavaScript behavior is call by value in primitive value and
call by reference in case of object."
Not exactly. In Javascript everything is passed by value all the time. If you pass an object, you actually pass a reference to the object, and that reference is passed by value.
Example:
var o = { name: 'first' };
// pass object reference to a function
use(o);
function use(x) {
// change the reference
x = { name: 'second' };
}
alert(o.name); // shows "first"
As the reference is passed by value to the function, changing the reference inside the function doesn't change the variable that was used to send the reference.
In your code you have only one array:
var temp = a; // copy the reference from a to temp
You have two variables that reference the same array, so any changes that you do to the array using one variable to access it will be visible when you look at the array using the other variable.
To get two separate arrays you have to specifically create a copy of it:
var temp = a.slice(0);
Note: Copying an array makes a shallow copy. That means that if you for example have an array of objects that you copy, you will have two arrays, but they will still share the same set of objects.
As you know, primitive values are passed by value, everything else is passed by reference. Primitives are boolean, number and string (and maybe consider null and undefined here). Everything else is an object and passed by reference.
While reading a book about JavaScript I stumbled across an example:
var names = new Array("Paul","Catherine","Steve");
var ages = new Array(31,29,34);
var concatArray;
concatArray = names.concat(ages);
My question is, why doesn't the variable concatArray need to be define as a new Array() in order to store the concatenated data for both arrays name and ages , but when I try to treat the concatArray as an array by adding another line of code "document.write(concatArray[0])", it works just like an array and shows me the data stored in the first element. I just wonder why I'm not declaring the concatArray as a new array, yet it still works as one.
You are declaring concatArray as a new array but the declaration is implicit. The concat function returns a new array which contains concatenated copies of the original two arrays. The type of concatArray is inferred from the return type of the concat function.
Variable don’t have a specific data type in Javascript like in other languages. You can assign a variable every value you want.
That means var concatArray; declares the variable but the value is undefined:
var concatArray;
alert(typeof concatArray === "undefined");
Only when assigning the return value of names.concat(ages) (an array) to concatArray it get’s that type:
var names = new Array("Paul","Catherine","Steve");
var ages = new Array(31,29,34);
var concatArray;
alert(typeof concatArray === "undefined");
concatArray = names.concat(ages);
alert(concatArray.constructor === Array);
Javascript doesn't care what the contents of the var are when it is declared; that is why you can declare var concatArray without needing to specify it as an array. Once you assign it a value and a type (as the result of the concat() function) javascript treats the var as an array.
Simply put, w3schools says it pretty concisely:
The concat() method is used to join two or more arrays.
This method does not change the existing arrays, it only returns a copy of the joined arrays.
w3schools
Looks like Andrew and Matthew beat me to it anyway.
Because Javascript is dynamically typed. A variable doesn't have a specifuc type, and an array is an object that you can assign to any variable.
When you declare a variable without assigning it a value, it just exists with an undefined value:
var answer;
// now the variable exists, but it doesn't have a value
answer = 42;
// now the variable has the numerical value 42
answer = "hello";
// now the numerical value has been replaced with the string value "hello"
answer = [];
// now the variable contains an empty array
answer[0] = 1337;
// now the variable contains an array that contains an item with the value 1337
answer = -1
// now the array is gone and the variable contains the value -1
I would make an answer slightly different of Andrew's one.
JavaScript variables are not strongly typed. You can put a string, then a number, then an object in the same variable. When you use the variable, the interpreter checks its current type is suitable for the usage you try to make. If you write:
var a = 45;
alert(a[0]);
a = [ 5 ];
alert(a[0]);
you will get successively undefined then 5.