1

From what I understand, when an array object is assigned to a new variable, that array object can be "referenced" between both variables, but the values themselve are mutable by either assigned variable.

At least that appears to be the case.

let variable1 = [6, 3, 2, 6, 7, 2, 9, 1, 5];
let variable2 = variable1;

for (i = 0; i < 10; i++) {
    variable2.unshift(i);
}

console.log(variable1);
> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 6, 3, 2, 6, 7, 2, 9, 1, 5]

Am I only able to timestamp the state of my data at a given point in the run time by creating a new array and pushing in the contents of the previous array, or is there another practice used? Thanks.

srb633
  • 793
  • 3
  • 8
  • 16
  • 1
    What are you trying to achieve exactly? – SMAKSS Jun 03 '20 at 14:50
  • Do you mean only copying an array? There are many ways, `[...array]` is more modern now, but it's only one level deep. https://stackoverflow.com/questions/7486085/copy-array-by-value –  Jun 03 '20 at 14:51
  • I'm wondering if it's possible to timestamp the state of my data at a given point in the run time between two variables without creating a new array. So variable 1 can be mutated separate from variable 2. Even though variable 2 was assigned the contents of variable1. – srb633 Jun 03 '20 at 14:52
  • 1
    When you set `variable2` equal to `variable1`, what you are actually doing is pointing towards a "location" of where the value of that variable is stored. So you are not *setting the value* of the variable, you are setting the *reference*. That means, when you modify the original variable (i.e. the variable being referenced), all other variables that point to that reference are also changed. You can prevent this by for example making a copy ("cloning") of the array i.e. `let variable2 = [...variable1];`. Interesting reading material: `primitives` vs `non primitives` – nbokmans Jun 03 '20 at 14:52
  • _I'm wondering if it's possible to timestamp the state of my data at a given point in the run time between two variables without creating a new array._: No. You need to copy the array. Both variables are pointing at the _same copy_ of the data. So to change one independent of the other you will need to clone the array – Matt Burland Jun 03 '20 at 14:53
  • Looks like it, similar answer at least. – srb633 Jun 03 '20 at 14:55

3 Answers3

2

Array.from()

const array2 = Array.from(array1)
console.log(array2)
1

If you don't want this behaviour, you have to make sure to use methods that generate a new array on every mutation of the original array.

To copy an array you can use Array.from(array) or ES6 [...array].

With that knowledge: For array.unshift(e) you can use ES6 array = [...array, e];

let variable1 = [6, 3, 2, 6, 7, 2, 9, 1, 5];
let variable2 = variable1;

for (i = 0; i < 10; i++) {
    variable2 = [...variable2, i];
}

console.log('var2', variable1);
console.log('var1', variable2);
odd_wizard
  • 21
  • 5
1

Javascript generally is always pass by value, but in the case when the variable refers to an object (including arrays) the "value" is a reference to that object.

When you change the value of a variable, it doesn't change the underlying object or primitive - instead it just points the variable to the new value.

However changing properties on an object (including arrays) will change the underlying object itself.

tl;dr

There is no way to capture the state at a given timepoint without making a complete copy of it.

How to create the copy

Depending on how your data is structured there are multiple ways you could go about to create a clone of it.

If it is just an array of primitives, e.g. an array of numbers / strings, a shallow copy of the array would suffice:

const arr = [1,2,3,"foo"];

// using array spread
const clone1  = [...arr];

// Array.from()
const clone2 = Array.from(arr);

// mapping the array
const clone3 = arr.map(e => e);

// push with spread
const clone4 = [];
clone4.push(...arr);

// good old for loop
const clone5 = [];
for(let i = 0; i < arr.length; i++)
  clone5.push(arr[i]);

If you have a deep data structure with nested objects / arrays, you need to do the shallow copying recursively to achieve a deep copy.

However there are already lots of good libraries that can handle these for you, for example lodash:

const value = [{a: 1}, {b: 2}, {c: ["a", "b"]}];

// using lodash _.cloneDeep to get a deep copy
const clone = _.cloneDeep(value);
Turtlefight
  • 9,420
  • 2
  • 23
  • 40
  • 1
    Okay, that's good to know. What made me original believe otherwise is that how I was cloning the arrays, seemed counter intuitive . I created a for loop each time I wanted to clone an array. So these answers have certainly condensed that for sure haha. – srb633 Jun 03 '20 at 14:59