1

Please check the following...

var arr = [["test", 1], ["test", 3], ["test", 5]]
var otherArr = arr.slice(0) //should be a new array with a copy of arr

When i evaluate arr === otherArr the result is FALSE.

When i do the following, trying to change first array value:

otherArr[0][1] = otherArr[0][1] + 5;

it also changes the original array (arr)

arr[0][1] === otherArr[0][1] evaluates to TRUE

but arr === otherArr evaluates to FALSE

Please help me understand this to avoid it.

guid0_py
  • 13
  • 3
  • Possible duplicate of [Is JavaScript a pass-by-reference or pass-by-value language?](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) – CRice Aug 29 '18 at 20:44
  • there's some answers below that help you understand. Here's a help on how to avoid, creating a copy of the entire array and it's values (deep copy): `otherArr = JSON.parse(JSON.stringify(arr))` – Calvin Nunes Aug 29 '18 at 20:49
  • I always was always fond of that from-to json trick. :) – Steven Spungin Aug 29 '18 at 20:53

4 Answers4

1

When i evaluate arr === otherArr the result is FALSE.

because a slice is not the same array.
it essentially is a copy of the arrays content.

When i do the following, trying to change first array value:

otherArr[0][1] = otherArr[0][1] + 5;

it also changes the original array (arr)

arr[0][1] === otherArr[0][1] evaluates to TRUE

but arr === otherArr evaluates to FALSE

yes because an array is a object and not a primitive value.

you are copying all the contents of arr into otherArr
but you are not creating copies of it's referenced objects.

if you had simple values in there like numbers, strings, boolean and probably even a regexp you could be sure that it would be copied.

if you access a sub array you need to create a slice of that sub array first too if you want an actual copy.

because arr is just pointing to the arrays. it does not contain them. they are references.


please also take a look at the comment from Calvin Nunes below your question:

you can create a deep copy by converting your array into a json string first and then back into an array:
otherArr = JSON.parse(JSON.stringify(arr))

keep in mind this works with simple stuff but if you want to copy objects that contain custom functions etc. you can forget about this.
they would not be added to the json representation and are lost.

json is just a format meant for transportation.
if you stumble across such a requirement in future you might want to consider rewriting your code instead.
this always leads to slow code.

you may want to recursively copy your array instead.
like.. walking through the array, if the member is of type array, walk through it too.

well.. there are various deep copy solutions out there. you just need to google for it.

GottZ
  • 4,824
  • 1
  • 36
  • 46
1

This is because the arrays are different objects from the slice()

arr === otherArr // false (different objects)

But the values stored in the arrays are the the same objects

 arr[0][1] === otherArr[0][1] 

If you do not want this behavior, you will need to do a deep copy of the array instead of a slice.

Here is some information on deep copy as it relates to arrays: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm

Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
  • so when i make a shalow copy, i'm only copying the references, not the values? arr and otherArr are allocated in different places but otherArr values are just references to arr? – guid0_py Aug 29 '18 at 21:03
1

The problem is

The slice() method returns a shallow copy […]

You are replicating just the first level, so you have to go deeper to made a copy. You could do:

    var arr = [["test", 1], ["test", 3], ["test", 5]]
    
    var otherArr = [...arr[0], ...arr[1], ...arr[2]]
    
    
    otherArr[0][1] = otherArr[0][1] + 5;
    
    console.log(arr)

The JSON.parse(JSON.stringify(arr)) method is the best solution in general.

Emeeus
  • 5,072
  • 2
  • 25
  • 37
1

This is best explained visually. Imagine arr as the following diagram. It's actually composed of 3 arrays, one referencing the other two:

arr [     0      ,      1      ]
          |             |
          v             v
      ['test', 1], ['test', 5]

When you did otherArr.slice(0), it creates a "shallow copy" - a new array but with identical contents to the original array. That means arr and otherArr are two separate arrays, but point to the same contents. arr[0] is the same object as otherArr[0], and arr[1] is the same object as otherArr[1]

arr      [     0      ,      1      ]
               |             |
               v             v
           ['test', 1], ['test', 5]
               ^             ^
               |             |
otherArr [     0      ,      1      ]

Now to your questions:

When i evaluate arr === otherArr the result is FALSE.

As mentioned above, arr and otherArr are two different arrays, causing === to fail. For non-primitives, === checks the identity (i.e. is it the same object?). Also note that === and == are NOT structural checks (i.e. do they look the same?).

When i do the following, trying to change first array value:

otherArr[0][1] = otherArr[0][1] + 5;

it also changes the original array (arr)

arr[0][1] === otherArr[0][1] evaluates to TRUE

Back to our diagram, what you're effectively doing is changing the contents of the object both arrays are referencing (in this case, the one that's now ['test', 6]).

arr      [     0      ,      1      ]
               |             |
               v             v
           ['test', 6], ['test', 5]
               ^             ^
               |             |
otherArr [     0      ,      1      ]
Community
  • 1
  • 1
Joseph
  • 117,725
  • 30
  • 181
  • 234
  • 1
    this is some quality dedication there. good work. you missed some commas though. i suppose arr[01] is weird – GottZ Aug 29 '18 at 21:04
  • @GuidoRaúlPereira you should always accept an answer and upvote answers that you think are good. even if they are not on your question. (just some random advice to someone new on stackoverflow) – GottZ Aug 29 '18 at 21:14
  • i think i did that with all answers @GottZ it doesn't add up (or show) because i'm new and there's a rule about that (don't remember now)... something about having minimal reputation – guid0_py Aug 29 '18 at 21:19
  • Still waiting for someone to post better ASCII art. :D – Joseph Aug 29 '18 at 21:22
  • @Joseph well.. you could use ↑ and ↓ though xD – GottZ Aug 30 '18 at 07:50