Copycat vs. Reference-cat 
Tags: codenewbie, beginners, javascript
Published: 2020-05-23 06:35:02

When dealing with data, developers oftentimes have to create copies in order to not mutate the dataset. In JavaScript, data types are either passed by value or passed by reference so there are different ways to make proper copies depending on what you're working with. And if you don't do it right, your copy won't end up being a copycat but turn out to be a reference-cat (terrible joke). Never heard of a reference-cat? Good, because it doesn't exist and your incorrectly copied variables shouldn't either. 

![simpsons copy gif](https://media.giphy.com/media/3orif28fKmGLblN1II/giphy.gif)

###Primitive Data Types
**Primitive data types are passed by value and are immutable. So if we change it, a new instance is created.** 

There are six primitive data types, checked by JavaScript's `typeof` operator:

  * Boolean: `typeof instanceName === 'boolean’`
  * String: `typeof instanceName === 'string'`
  * Number: `typeof instanceName === 'number'`
  * undefined: `typeof instanceName === 'undefined'`
  * BigInt: `typeof instanceName === 'bigint'`
  * Symbol: `typeof instanceName === 'symbol'`

####Making a Copy of a Primitive Data Type
To make a copy, all you have to do is create a new variable and assign its value to the variable you want to copy. 

```javascript
let str1 = 'noodles'; 
str1; // 'noodles'
let str2 = str1; 
str2; // 'noodles'
str1 === str2; // true
str1 = 'pizza' // 'pizza'
str1 === str2; // false
str2; // 'noodles'
```
Above, I've created a new variable `str2` and assigned its value to `str1`. JavaScript has allocated a separate memory spot for `str2` so `str1`'s value is reassigned. `str2` is not affected because it is independent of `str1`.

###Non-Primitive Data Types
**Non-primitive data types, however, are passed by reference and are mutable.** So if we change it, it can be difficult to keep track of and wacky things can happen if you're not careful. **Non-primitive data types include Object, Array, Set, and Map.** This means that arrays and objects assigned to a variable do not actually contain the other variable's values but rather point to the data type's reference in memory. 

```javascript
let obj1 = {1: 'noodles', 2: 'pizza'}; 
obj1; // {1: 'noodles', 2: 'pizza'}
let obj2 = obj1;
obj2; // {1: 'noodles', 2: 'pizza'}
obj1 === obj2; // true
obj1[3] = cake; 
obj1; // {1: 'noodles', 2: 'pizza', 3: 'cake'}
obj2; // {1: 'noodles', 2: 'pizza', 3: 'cake'}
```

On the surface, `arr2` appears to get `arr1`'s values, but it's only pointing to `arr1`'s reference in memory. Any changes to made to `arr1` will be reflected in `arr2` and also vice versa as they are both pointing to the same reference.

####Making a Copy of a Non-Primitive Data Type
There are a few different ways to make copies of objects in JavaScript. Depending on your needs, some of the methods will only shallow copy the object while others can support a deep copy.

####Spread Operator
Using the spread operator will make a shallow copy of your object. It works great for all objects including arrays and objects.
```javascript
const arr1 = ['noodles', 'pizza'];
const copyArr = [...arr1];
copyArr; // ['noodles', 'pizza']

const obj1 = {1: 'noodles', 2: 'pizza'}; 
const copyObj = {...obj1};
copyObj; // {1: 'noodles', 2: 'pizza'}
```

####Object.assign() 
Using `Object.assign()` will produce a shallow copy of your JavaScript object. Make sure to pass in an empty `{}` as the target argument so there is no mutation to be had.

```javascript
//syntax
Object.assign(target, ...sources);
let obj1 = {1: 'noodles', 2: 'pizza'}; 
let copyObj = Object.assign({}, obj1};  // { '1': 'noodles', '2': 'pizza' }
obj1 === copyObj; // false;
obj1[3] = 'cake';
obj1;  // {1: 'noodles', 2: 'pizza', 3: 'cake'}
obj2; // {1: 'noodles', 2: 'pizza'}
```

####Object.fromEntries(Object.entries())
Another shallow copy method for your JavaScript object is to use `Object.fromEntries()` in conjunction with `Object.entries()`. Introduced in ECMAScript 2019, `Object.fromEntries()` transforms a list of key-value pairs into an object. Using `Object.entries()` will turn the object you want to copy into key-value pairs, then using `Object.fromEntries()` will turn that into your very own object copy.

```javascript
let obj1 = {1: 'noodles', 2: 'pizza'}; 
let copyObj = Object.fromEntries(Object.entries(obj1));
copyObj; // {1: 'noodles', 2: 'pizza'}
```

####Array.from()
Similarly to above, you can use `Array.from()` to make shallow copies of arrays.
```javascript
const arr1 = ['noodles', 'pizza'];
const copyArr = Array.from(arr1);
copyArr; // ['noodles', 'pizza']
```
####JSON
For a deeper copy of your objects, you can use `JSON` to first stringify your object to JSON and then parse the string back into an object. However, using JSON to make a deep copy only works when the source object is JSON safe. 

```javascript
const obj1 = {1: 'noodles', 2: 'pizza', 3: 'cake'}; 
const copyObj = JSON.parse(JSON.stringify(obj1));
copyObj; // {1: 'noodles', 2: 'pizza', 3: 'cake'}
```

####Alternatives Using Libraries
Though my copycat needs are typically met with one of the above methods, there are several external libraries out there that will deep copy your objects. These include [Lodash's cloneDeep()](https://www.npmjs.com/package/lodash.clonedeep) and [Underscore's clone()](https://underscorejs.org/).

Clone away with any one of these methods knowing your copies are copycats and not those pesky reference-cats!

 
*Resources*
[Object.fromEntries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries)
[3 Ways to Clone Objects in JavaScript](https://www.samanthaming.com/tidbits/70-3-ways-to-clone-objects/)
[JavaScript Data Types and Data Structures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures)