얕은 복사 vs 깊은 복사

Jiwon Yoo·2023년 3월 2일
0

프론트엔드

목록 보기
11/38

원시 자료형을 할당한 변수를 다른 변수에 할당하면 값 자체의 복사가 일어난다. 값 자체가 복사된다는 것은 둘 중 하나의 값을 변경해도 다른 하나에는 영향을 미치지 않는다는 것을 의미한다.

예시

let num = 4;
let newNum = num;
console.log(num); // 4
console.log(newNum); // 4
console.log(num === newNum); // true
newNum = 6;
console.log(num); // 4
console.log(newNum); // 6
console.log(num === newNum); // false

반면, 참조 자료형은 임의의 저장공간에 값을 저장하고 그 저장공간을 참조하는 주소를 메모리에 저장하기 때문에 다른 변수에 할당할 경우 값 자체가 아닌 메모리에 저장되어 있는 주소가 복사된다. 참조 자료형이 저장된 변수를 다른 변수에 할당할 경우, 두 변수는 같은 주소를 참조하고 있을 뿐 값 자체가 복사 되었다고 볼 수 없다.

예시

let arr = [0, 1, 2, 3];
let newArr = arr;
console.log(arr); // [0, 1, 2, 3]
console.log(newArr); // [0, 1, 2, 3]
console.log(arr === newArr) // true
newArr.push(4);
console.log(arr); // [0, 1, 2, 3, 4]
console.log(newArr); // [0, 1, 2, 3, 4]
console.log(arr === newArr) // true

얕은 복사

참조 자료형이 몇 단계로 중첩되어 있던지, 한 단계까지만 복사하는 것을 얕은 복사라고 한다. 아래 설명할 slice(), Object.assign(), spread syntax 등의 방법으로 참조 자료형을 복사하면, 중첩된 구조 중 한 단계까지만 복사가 가능하다.

배열 복사하기

1) slice()

let arr = [0, 1, 2, 3]; //주솟값 9876
let copiedArr = arr.slice(); //주솟값 1234
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]

2) spread syntax

let arr = [0, 1, 2, 3]; //주솟값 9876
let copiedArr = [...arr]; //주솟값 1234
console.log(copiedArr); // [0, 1, 2, 3]
console.log(arr === copiedArr); // false
copiedArr.push(4);
console.log(copiedArr); // [0, 1, 2, 3, 4]
console.log(arr); // [0, 1, 2, 3]

새롭게 생성된 배열은 원본 배열과 같은 요소를 갖지만 참조하고 있는 주소는 다르다. 주소가 다르기 때문에 복사한 배열에 요소를 추가해도 원본 배열에는 추가되지 않는다.

객체 복사하기

1) Object.assign()

let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = Object.assign({}, obj);
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

2) spread syntax

let obj = { firstName: "coding", lastName: "kim" };
let copiedObj = {...obj};
console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
console.log(obj === copiedObj) // false

중첩된 참조 자료형에 얕은 복사를 사용하면?

한 단계까지만 복사되고 안에 중첩된 자료형은 같은 주소를 참조하고 있다.

깊은 복사

참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사하는 것은 깊은 복사(deep copy)라고 한다. 그러나 JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없다. 단, JavaScript의 다른 문법을 응용하면 깊은 복사와 같은 결과물을 만들어 낼 수 있다.

1) JSON.stringify()와 JSON.parse()

JSON.stringify()는 참조 자료형을 문자열 형태로 변환하여 반환하고, JSON.parse()는 문자열의 형태를 객체로 변환하여 반환한다. 먼저 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환하고, 반환된 값에 다시 JSON.parse()를 사용하면, 깊은 복사와 같은 결과물을 반환할 수 있다.

const arr = [1, 2, [3, 4]];
const copiedArr = JSON.parse(JSON.stringify(arr));
console.log(arr); // [1, 2, [3, 4]]
console.log(copiedArr); // [1, 2, [3, 4]]
console.log(arr === copiedArr) // false
console.log(arr[2] === copiedArr[2]) // false

하지만 이 방법을 사용하면 함수가 null로 바뀌게 된다. 따라서 이 방법은 완전한 깊은 복사 방법이라고 보기 어렵다.

2) 외부 라이브러리 사용

node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 설치하면 깊은 복사가 가능하다.

profile
새싹 개발자 🌱

0개의 댓글