# 깊은복사와 얕은 복사

---

## 🌷  얕은 복사와 깊은 복사

최근들어 내가 기본이 아직 많이 부족하다는 것을 정말 많이 느낀다. 짧은 시간 공부하고 취업해서 개발자라고 이야기를 하고 있으니.. 그럴 수 밖에. 아직 어디를 가면 스스로를 개발자라고 소개하기가 부끄러울 때가 많다. 그래서 기본이 부족했던 부분들을 다시 열심히 공부해서 차곡차곡 쌓아야겠다는 생각이들었다.

오늘은 얕은 복사와 깊은 복사에 대해 조금 더 깊게 확인하고 제대로 이해를 해봐야겠다고 생각하고 정리를 해봤다. 지금 회사 입사를 할 때 받았던 질문이었는데 그 때는 정말 두루뭉술하게만 대답하고 이해했던 것 같아서, 이참에 제대로 알고 가보자!

## 🖐🏻  얕은 복사와 깊은 복사를 알아보기 전에,

---

### 📝  데이터 타입

* 원시형
    
* 참조형
    

👉🏻  [자세히 알아보기](https://github.com/kordobby/amazon/blob/main/save/JavaScript/core_javascript/part1_data-type/1-1.md)

### 📝  데이터 타입에 따른 메모리 동작

* 원시형
    

```jsx
// 변수 poke 에 문자열 "피카츄"를 할당
var poke = "피카츄";

/* 메모리 동작

1. &17 의 값에 undefined 할당
2. 식별자 poke 에 &17 할당
3. 새로운 공간인 &27 에 "피카츄"을 저장
4. poke 에 &27할당
*/

* & : 메모리 주소를 의미 ex. &27 는 메모리의 27번 주소
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700044373945/9432f1b2-826d-40c9-afbc-b7ff37ad0c7e.png align="center")

* 참조형 - property 하나를 가질 경우
    

```jsx
// 변수 startingPokemon 에 객체를 할당
var starting = {
	name : "이상해씨"
};

/* 메모리 동작

1. &18의 값에 undefined 를 저장
2. 식별자 starting 에 &28 을 할당 "주소의 이름이 됨!"
3. 새로운 공간인 &28 에 객체를 저장할 공간의 주소인 &37 를 할당
  - 즉, &28 번 주소의 값이 &37 이 됨
  - 원시형 데이터는 &27번 주소의 값이 "피카츄"
4. &12(name) 에 "이상해씨" 라는 문자열 값을 저장
5. starting 에 &28 을 할당

* 결과
  - starting 변수의 값은 &18
  - &18 에는 객체 프로퍼티를 저장하고 있는 저장 공간의 주솟값(&37)를 가짐
  - 객체는 주솟값을 이용해 참조
*/
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700044387497/7d7d4733-8a96-48c4-a2b9-990706f0653e.png align="center")

* 참조형 - 2가지 이상의 프로퍼티를 가질 경우
    

```jsx
// 변수 startingPokemon 에 객체를 할당
var myPoke = {
	first : "피카츄"
   second : "이상해씨"
};
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700044405058/5a1c7101-584a-46da-8a4e-3e834b61ab60.png align="center")

## 🙋🏻‍♀️ 복사의 종류

> **deep copy** : A deep copy means that all of the values of the new variable are copied and **disconnected from the original** variable.
> 
> **shallow copy** : A shallow copy means that certain (sub-)values are **still connected to the original** variable.

### 얕은 복사

* 참조 복사 (reference copy)
    
* 객체 복사 (object copy)
    
* ex ) `Array.prototype.slice()`, `Object.assign()`, Spread 연산자 (전개 연산자)
    

### 깊은 복사

* 깊은 복사 (deep copy)
    
* ex) `JSON.parse()` , `JSON.stringify` , 재귀 함수를 구현한 복사, `Lodash` 라이브러리 사용
    

```jsx
/* 1. 중첩된 객체 예시 */
var startingPokemon = {
		generation: '1세대',
		pokemon : {
			name : "이상해씨",
			number : 1
		}		
	};

# 참조 복사
var referenceCopy = startingPokemon;

# 객체 복사
var shallowCopy = shallowCopy(startingPokemon);

const shallowCopy = ( targetObj ) => {
	var returnObj = {};

	// targetObj 를 순회하며 
  // key-targetObj[key] (key-value) 쌍으로 returnObj 추가
  for (var key in targetObj) {
		returnObj[key] = targetObj[key];
	}
  
	return returnObj;  // 새로 만들어진 객체를 반환
};

# 깊은 복사
var deepCopy = deepCopy(startingPokemon);

const deepCopy = ( targetObj ) => {
	var returnValue = {};
	
	if (typeof targetObj === 'object' && targetObj !== null) {

    // targetObj 가 객체라면 프로퍼티를 재귀 형식으로 호출
		for (var key in targetObj) {
			returnValue[key] = deepCopy(targetObj[key]);
		}
	} else {
    // target 이 객체가 아니라면 값 반환
		returnValue = target;
	}
	return returnObj;
}
```

## 💁🏻‍♀️ 복사 결과

### 1️⃣  얕은 복사 - 참조 복사 (주솟값 복사)

```jsx
# 참조 복사 // referenceCopy

var starting = {
		generation: '1세대',
		pokemon : {
			name : "이상해씨",
			number : 1
		}		
	};

var rfc = starting;
```

### 복사 결과 확인

```jsx
# 원본객체

&11 (shallowCopy)
	- &21
		- &31 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

```jsx
# 참조 복사

&12 (shallowCopy)
	- &21
		- &31 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700044312597/12fa9512-1e2a-4cdf-bbc9-c49a8e16536e.png align="center")

### 2️⃣  얕은 복사 - 객체 복사

```jsx
// 객체 복사 - shallowCopy

var starting = {
		generation: '1세대',
		pokemon : {
			name : "이상해씨",
			number : 1
		}		
	};

var sc = shallowCopy(starting);

const shallowCopy = ( targetObj ) => {
	var returnObj = {};

	// targetObj 를 순회하며 
    // key-targetObj[key] (key-value) 쌍으로 returnObj 추가
  for (var key in targetObj) {
		returnObj[key] = targetObj[key];
		/*
			returnObj['generation'] = targetObj['generation'];
			returnObj['pokemon'] = targetObj['pokemon']; // 객체를 가져옴
		*/
	}
  
	return returnObj;  // 새로 만들어진 객체를 반환
};
```

* 복사 결과 확인
    

```jsx
# 원본객체

&11 (shallowCopy)
	- &21
		- &31 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

```jsx
# 객체 복사

&13 (shallowCopy)
	- &26
		- &51 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700044233683/35c52a24-1e9e-4578-a6ac-8baaa9e1f36a.png align="center")

### 3️⃣  깊은 복사

```jsx
# 깊은 복사

var starting = {
		generation: '1세대',
		pokemon : {
			name : "이상해씨",
			number : 1
		}		
	};

var deepCopy = deepCopy(starting);

const deepCopy = ( targetObj ) => {
	var returnValue = {};
	
	if (typeof targetObj === 'object' && targetObj !== null) {

    // targetObj 가 객체라면 프로퍼티를 재귀 형식으로 호출
		for (var key in targetObj) {
			returnValue[key] = deepCopy(targetObj[key]);
		}
	} else {
    // target 이 객체가 아니라면 값 반환
		returnValue = target;
	}
	return returnObj;
}
```

* 복사 결과
    
    * 모든 주소의 값이 달라짐
        

```jsx
# 원본객체

&11 (shallowCopy)
	- &21
		- &31 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

```jsx
# 깊은 복사

&14 (dc)
	- &27
		- &61 (generation)
		- &62 (pokemon)
			- &71 (name) : "이상해씨"
			- &72 (number) : 1
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1700044208063/060cc352-cc7b-48a1-93ed-7e38e21dca6a.png align="center")

## 👩🏻‍💻  각 객체들의 주솟값 비교 모아보기

* 🔗  : 원본 객체와 연결
    
* 🆕  : 원본 객체가 아닌 새로운 값
    

```jsx
# 원본객체

&11 (shallowCopy)
	- &21
		- &31 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

```jsx
# 참조 복사

&12 (shallowCopy)
	- &21 🔗
		- &31 (generation)
		- &32 (pokemon)
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

```jsx
# 깊은 복사

&14 (dc)
	- &27 🆕 
		- &61 (generation) 🆕 
		- &62 (pokemon) 🆕 
			- &71 (name) : "이상해씨"
			- &72 (number) : 1
```

```jsx
# 얕은 복사

&13 (shallowCopy)
	- &26 🆕 
		- &51 (generation) 🆕 
		- &32 (pokemon) 🔗
			- &24 (name) : "이상해씨"
			- &25 (number) : 1
```

---

## 🌝  결론

* 복사한 객체가 원래 객체에 연결이 되어있다면 (주솟값을 참고) 얕은복사
    
* 복사한 객체가 원래 객체에 연결되어 있지 않다면 깊은복사
    
* 느낀 점
    
    * 직접 데이터 주소 구조를 그려가며 이해해보니 확 머리에 들어왔던… 어렵다고 이해할 수 없는 것들은 없는 것 같다. 열심히 파다보면 역시 내 것이 되는 ㅠ\_ㅠ 열심히 하자..!
        
* 혹시 내용 중 틀린 점이 있다면 알려주세요! 응애 개발자의 성장을 위해..!
    

---

### 참고

* [https://github.com/kordobby/amazon/blob/main/save/JavaScript/core\_javascript/part1\_data-type/1-1.md](https://github.com/kordobby/amazon/blob/main/save/JavaScript/core_javascript/part1_data-type/1-1.md)
    
* [https://www.youtube.com/watch?v=QFIfI8MIURQ](https://github.com/kordobby/amazon/blob/main/save/JavaScript/core_javascript/part1_data-type/1-1.md)
    
* [https://ladiescheong.tistory.com/48](https://github.com/kordobby/amazon/blob/main/save/JavaScript/core_javascript/part1_data-type/1-1.md)
