빙하기 같았던 취업 시장을 뚫으려 공부했던 깊은 복사 / 얕은 복사 개념이 아무래도 애매해서, 신입이 들어왔을 때
'헉! 저 사람은 깊은 복사와 얕은 복사도 잘 모르나 봐!' 라고 공공연하게 조리돌림을 당해 창피를 당할 수도 있겠단 생각에 급하게 정리해본 깊은 복사와 얕은 복사. 이렇게 정리해 두면 더 이상 까먹지 않겠지? 분명 또 까먹고 말겠지.
1. 깊은 복사 / 얕은 복사란?
Javascript 의 얕은 복사는 객체의 참조값(주소 값)을 복사하고, 깊은 복사는 객체의 실제 값을 복사한단다.
복사된 녀석(카피)의 값을 변경했을 때, 원본 녀석도 바뀌면 얕은 복사,
복사된 녀석(카피)의 값을 변경해도 그대로면 깊은 복사이다.
이렇게만 정리하니 '원시값' 과 '참조값' 개념이 좀 헷갈린다. 예제를 통해 알아보자.
대입을 통한 원시값(변수) 복사 -> 깊은 복사가 된다.
const a = 'a';
let b = 'b';
b = 'c';
console.log(a, b);
================================
출력 (원본은 그대로!)
a c
대입을 통한 참조값(객체) 복사 -> 얕은 복사가 된다. (원본은 그대로다!)
const a = {
one: 1,
two: 2,
};
let b = a;
b.one = 333;
console.log(a, b);
================================
출력 (원본이 변했다!)
{ one: 333, two: 2 }
{ one: 333, two: 2 }
그럼 이제 참조값을 복사하기 위해서는 어떻게 해야하는지를 알아보자. 이게 또 골치 아프다.
2. 참조 타입의 얕은 복사
참조값을 그냥 대입하면 위처럼 얕은 복사가 된다. 그건 JavaScript 의 참조값들은 주소를 가르키고 있기 때문이다.
그럼 참조값을 깊은 복사하려면 어떻게 해야 하냐?
slice() 와 spread 연산자, Object.asign() 등등을 이용한다면, 1depth 는 깊복, 2depth 는 얕복을 하게 할 수다. 이 녀석들을 참조 타입의 얕은 복사라 부른다.
const original = [
{
a: 1,
b: 2,
},
true,
];
const copy = original.slice();
// 복사된 배열만 변경.
copy[0].a = 99;
copy[1] = false;
console.log(original);
// [ { a: 99, b: 2 }, true ]
console.log(copy);
// [ { a: 99, b: 2 }, false ]
a 는 얕복이라 원본이랑 카피본 둘 다 99로 바뀌었고 true 는 깊복이라 copy 만 false 로 바뀌었다. 따로국밥이다.
3. 참조값의 깊은 복사 방법
const copy = JSON.parse(JSON.stringify(object));
이 녀석, 프론트 개발자라면 실무에서 많이 써봤을 녀석이다.
const object = {
a: "a",
number: {
one: 1,
two: 2,
},
arr: [1, 2, [3, 4]],
};
const copy = JSON.parse(JSON.stringify(object));
copy.number.one = 3;
copy.arr[2].push(5);
console.log(object); // { a: 'a', number: { one: 1, two: 2 }, arr: [ 1, 2, [ 3, 4 ] ] }
console.log(copy); // { a: 'a', number: { one: 3, two: 2 }, arr: [ 1, 2, [ 3, 4, 5 ] ] }
이렇게 copy 를 만들면 copy 를 변경한다고 같이 변경되지 않는 걸 확인할 수 있다.
찾아보며 알았는데 이 녀석은 객체 안에 함수가 있으면 undefinded가 되어서 나오는 한계가 있었다.
4. structuredClone
찾아보다 나온 녀석.
우리가 알고 있는 lodash 나 es-toolkit 을 사용하지 않고도, JSON.parse()보다 강력한 복사 메소드가 js 에는 있었다.
아직은 일부 브라우저(Web API 형태로) 및 환경에서만 지원한다고 하는데, 깊은 복사를 제공하는 녀석이다.
순환되는 데이터 구조를 처리할 수 있고, 내장 데이터 타입(Map 같은 녀석)을 지원할 수 있으며 일반적으로 더 강력하고 더 빠르다고 한다.
const obj1 = {
a: 1,
b: 2,
c: function () { return this.a + this.b }, // (함수는 복사할 수 없다.)
d: new Date(), // Date 타입으로 가져온다!
e: 1n //BigInt 도 된다!
}
const obj2 = structuredClone(obj1);
5. 마치며
우리고 언어로 사용하고 있는 복사는 대체로 깊은 복사일 것이다.
복사된 내 민증에 낙서를 한다고 원본 민증에 낙서가 되지 않는 것처럼. 생활 레벨에서 복사에서는 원본과 같이 움직인다는 개념은 존재하지 않는다. 그것만 기억하면 쉽다. 우리가 보통 사용하는 복사라는 개념은 깊은 복사이고, 얕은 복사란 원본과 같이 움직이는 연결과 가깝다는 점.
도움받은 곳
https://bbangson.tistory.com/78 [뺑슨 - JavaScript 깊은 복사 얕은 복사]
'FRONT' 카테고리의 다른 글
| 플러터 개쩐다 (2) | 2025.01.19 |
|---|---|
| 내가 셋을 세면 시작하는 거야...!! 원!!!!! 투!!! 쓰리.js (2) | 2024.11.01 |