问题
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.
回答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      ]
回答2:
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
回答3:
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.
回答4:
When i evaluate
arr === otherArrthe 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 TRUEbut
arr === otherArrevaluates 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.
来源:https://stackoverflow.com/questions/52085758/non-equals-arrays-changing-values-at-same-time-javascript