I am trying to understand how shallow copy works with map
and without map
on an array.
const arr = [
{
name: 'example',
inner: {
title: 'test'
}
}
]
const copy = arr.map(a => ({
...a
}))
copy[0].name = 'name1'
copy[0].inner.title = 'title1'
Updating name
prop on the copy
will not affect the original array arr
. However, updating inner.title
will modify both copy
and arr
. As far as I understand, in a shallow copy only top/first level props are copied, nested objects still share the same reference.
However, now if I create a shallow copy without using map
then even the first/top level props will share the same reference I think or at least updating first/top level props on the copy will affect the original one.
// same arr above
const copy2 = [...arr];
copy2[0].name = 'name2';
copy2[0].inner.title = 'title2';
Now, the original arr
's name
value is 'name2' and inner.title
value is 'title2'. Why is that? What is the exact difference between two code snippets, how map
plays a role in shallow copy?
It's easiest to start with your copy2
as that's simpler. When you do this:
const copy2 = [...arr];
that is use the "spread" operator on an array, you make exactly a "shallow copy" of the array. This means that copy2
and arr
are references to different arrays (arrays that are in different memory locations, if you want to think of it that way, although memory management is just an implementation detail of the JS engine rather than something JS developers have to think about), but their contents, if they are objects (which they are here) are still referencing the same things. That is arr[0]
and copy2[0]
are literally the same object - in the same memory location, if you want to think of it that way - and mutating one will mutate the other just the same (as your code snippet and its result proves).
copy
though is doing something rather different:
const copy = arr.map(a => ({
...a
}))
While you're also using the "spread" operator to here to again make "shallow copies", what it is that you're copying is different. It's not the array you're copying - it's a
, which stands for an element of the array. (This affects all elements because that's what map
does.) So what you're doing here is making a new array called copy
, that isn't a reference to any previously existing array, whose elements are shallow copies of the corresponding elements in a
. Which is why changing copy[0].name
doesn't affect arr[0].name
, because those 2 objects are references to different things - due to the shallow copy.
TLDR: the key difference is that in copy2
it's the whole array that you've made a shallow copy of, and because it's shallow, mutations to its object elements mutate the elements of the original. Whereas with copy
you've actually shallowly copied each individual element in in, thereby going "one level deeper" if you like.