## DEV Community

Joseph Trettevik

Posted on • Updated on

# Cloning an Array in JavaScript: A Cautionary Tale

In JavaScript, don’t do this:

``````let a = [1, 2, 3]
let b = a
``````

Got it? Okay cool, we’re done here…pack it up guys. 📦

Seriously though, if you’re new to JavaScript, or even not so new, make sure you know the right way to clone an array because if you mess it up, it can lead to some pretty horrible bugs.

## A Cautionary Tale

There I was, coding away on my final project at Flatiron School. You know, the big one that’s gonna show the world what I’m made of. I didn’t realize it at the time, but I was about to write some code that was gonna land me in a world of hurt.

Here's a version of what I wrote. I stripped it down to make the mistake easier to spot.

``````const numbers = [ 1, 7, 4 ]

const array = [
{a: 'value1'},
{a: 'value2'},
{a: 'value3'}
]

array.forEach( obj => obj['b'] = numbers)

console.log('array before change = ', array)
//-> array before change =  [
//     { a: 'value1', b: [ 1, 7, 4 ] },
//     { a: 'value2', b: [ 1, 7, 4 ] },
//     { a: 'value3', b: [ 1, 7, 4 ] }
// ]

array[0].b.push(5)

console.log('array after change = ', array)
//-> array after change =  [
//     { a: 'value1', b: [ 1, 7, 4, 5 ] },
//     { a: 'value2', b: [ 1, 7, 4, 5 ] },
//     { a: 'value3', b: [ 1, 7, 4, 5 ] }
// ]
``````

That's right Lego Batman, what the heck? We only added a 5 to one of the arrays, but somehow a 5 got added to all of them.

Now in this example, the error in the code is pretty easy to spot. However, if like me you make this mistake in a much more complicated algorithm, you're gonna be pulling your hair out. So don't do it!

### Take Away

``````let a = [1, 2, 3]
let b = a //Don't clone an array like this
``````
• This code does not create a copy of 'a' and assign it to 'b', it creates another reference to the original array and assigns that new reference to 'b'.
• Any change to 'a' or 'b' will cause the same change in the other, because 'a' and 'b' are just references to the same array in memory.

## The Right Way to Copy an Array

``````let a = [1, 2, 3]

//Old ES5 way (aka oldie but a goodie)
let b = a.slice()

//New ES6 way #1
let c = [...a]

//New ES6 way #2
let d = Array.from(a)

//New ES6 way #3
let e = Object.assign([], a)

b[1] = 9
c.push(4)
d.unshift(-1, 0)
e.shift()

console.log('a = ', a)
//-> a =  [ 1, 2, 3 ]

console.log('b = ', b)
//-> b =  [ 1, 0, 3 ]

console.log('c = ', c)
//-> c =  [ 1, 2, 3, 4 ]

console.log('d = ', d)
//-> d =  [ -1, 0, 1, 2, 3 ]

console.log('e = ', e)
//-> e =  [ 2, 3 ]
``````

Well I'm happy, Lego Batman and Robin are giving each other high fives...we're good now, right? Well...not quite.

## Beware of Shallow Copies

What happens if we use proper array cloning methods on deeply nested arrays?

``````let a = [1, [2, 4], [3, 6]]

let b = a.slice()
let c = [...a]
let d = Array.from(a)
let e = Object.assign([], a)

b[0] = 100
b[1][0] = 9

console.log('a = ', a)
console.log('b = ', b)
console.log('c = ', c)
console.log('d = ', d)
console.log('e = ', e)
//-> a =  [ 1, [ 9, 4 ], [ 3, 6 ] ]
//-> b =  [ 100, [ 9, 4 ], [ 3, 6 ] ]
//-> c =  [ 1, [ 9, 4 ], [ 3, 6 ] ]
//-> d =  [ 1, [ 9, 4 ], [ 3, 6 ] ]
//-> e =  [ 1, [ 9, 4 ], [ 3, 6 ] ]
``````

I'm as surprised as you are, Lego Batman. Reassigning the b[0] to 100 only affected array 'b', but reassigning b[1][0] = 9 changed all the arrays?

If we look into this, we find that even the proper methods for copying arrays in JavaScript are only doing a shallow copy. This means only the first level of the nested array is being copied. The deeper levels are being referenced.

This comes back to the fact that variables store references to arrays and objects, not the array or object itself. So when 'a' is cloned, the above methods are copying references to the nested arrays into a copy of the outermost array.

Primitives (string, number, bigint, boolean, null, undefined, and symbol), on the other hand, are actually copied into the new array.

If you want to deeply clone your arrays, you'll either have to write your own algorithm to do that, or you can use a third party method like the Lodash method _.clonedeep().

## Conclusion

When cloning arrays in Javascript, use one of these methods (these examples assume arry = [1, 2, 3]):

• let clonedArray = arry.slice()
• let clonedArray = [...arry]
• let clonedArray = Array.from(arry)
• let clonedArray = Object.assign([], arry)

Beware of the fact that these methods only do a shallow copy. If you need to deeply clone a nested array, do one of the following: