개발 공부 일지/JavaScript

[JS] 얕은 복사, 깊은 복사

dev-hpk 2024. 9. 19. 18:07

JavaScript에서 spread 구문(...)은 배열과 객체를 복사하거나 병합하는데 매우 유용한 문법입니다. 특히 간결한 코드로 데이터를 다룰 수 있어 자주 사용됩니다. 하지만, spread 구문이 항상 얕은 복사(shallow copy)를 수행한다는 점을 이해하는 것이 중요합니다. 이 글에서는 얕은 복사깊은 복사의 차이점을 설명하고, 어떤 경우에 spread 구문이 적합한지, 그리고 깊은 복사가 필요한 경우 어떻게 처리해야 하는지 알아보겠습니다.

 

 

 

얕은 복사, 깊은 복사 - 커버 이미지

 

자바스크립트의 얕은 복사와 깊은 복사

 

목차

 

1. 얕은 복사

2. 깊은 복사

3. 적절한 사용법

4. 얕은 복사의 위험성

마무리

추천글

 

얕은 복사

얕은 복사는 객체나 배열의 참조값을 복사하는 것을 의미합니다. 즉, 배열이나 객체의 각 요소가 원시형(Primitive) 데이터일 경우에는 복사된 값이 완전히 독립적이지만, 참조형(Reference) 데이터일 경우에는 원본 데이터와 참조를 공유합니다.

 

얕은 복사 이미지

 

얕은 복사의 특징

  • 원시형 데이터(Primitive): 숫자(Number), 문자열(String), 불리언(Boolean) 등의 값은 독립적으로 복사됩니다.
  • 참조형 데이터(Reference): 배열(Array), 객체(Object), 함수(Function)는 같은 메모리 참조를 공유하게 됩니다.

얕은 복사 예시

const original = {
  name: 'Kim',
  age: 30,
  details: {
    city: 'Seoul',
    hobby: 'coding'
  }
};

const copy = { ...original };  // 얕은 복사

// 복사된 객체 수정
copy.name = 'Kang';  
copy.details.city = 'Busan';

console.log(original.name); // 'Kim' : 기본형 -> 원본에 영향 없음
console.log(original.details.city); // 'Busan' : 참조형 -> 원본 객체에 영향

 

위 코드를 보면, copy.name을 수정해도 original.name은 변하지 않지만, copy.details.city를 수정하면 original.details.city도 함께 변하는 것을 확인할 수 있습니다. 이는 spread 구문얕은 복사를 수행했기 때문입니다. 원시형 데이터인 name은 원본과 복사본이 독립적이고, 참조형 데이터인 details 객체는 원본과 복사본이 동일한 참조를 가리키고 있습니다.

 

 

깊은 복사

깊은 복사는 객체나 배열의 실제값을 완전히 독립적으로 복사하는 것을 의미합니다. 원본 데이터와 복사본이 완전히 분리되어 있어, 복사된 객체의 값을 수정해도 원본 데이터에 아무런 영향을 미치지 않습니다.

 

깊은 복사 이미지

 

JSON을 이용한 깊은 복사

가장 간단한 방법 중 하나는 JSON.parse와 JSON.stringify를 이용하는 것입니다. 복사할 객체를 String 객체로 변경하고 String 객체를 JSON 객체로 변경하면 깊은 복사가 가능합니다. JSON을 이용한 깊은 복사 방법은 함수나 undefined 값을 복사하지 못하는 한계가 있습니다.

const original = {
  name: 'Kim',
  age: 30,
  details: {
    city: 'Seoul',
    hobby: 'coding'
  }
};

const copy = JSON.parse(JSON.stringify(original));  // 깊은 복사

// 복사된 객체 수정
copy.name = 'Kang';  
copy.details.city = 'Busan';

console.log(original.name); // 'Kim' : 기본형 -> 원본에 영향 없음
console.log(original.details.city); // 'Seoul' : 참조형 -> 원본에 영향 없음
console.log(copy.name); // 'Kang' : 기본형 -> 원본과 독립적인 값
console.log(copy.details.city); // 'Busan' : 참조형 -> 원본과 독립적인 값

Lodash 라이브러리 사용한 깊은 복사

https://lodash.com/docs/4.17.15#cloneDeep

 

Lodash Documentation

_(value) source Creates a lodash object which wraps value to enable implicit method chain sequences. Methods that operate on and return arrays, collections, and functions can be chained together. Methods that retrieve a single value or may return a primiti

lodash.com

재귀 함수를 이용한 깊은 복사

직접 재귀적으로 객체나 배열의 속성을 복사하는 방식도 가능합니다.

let origin = {
    a: 1,
    b: { 
    	c: 2
    }
};

function copyObj(origin) {
    let res = {};

    for (let key in origin) {
      if (typeof origin[key] === 'object') {
          res[key] = copyObj(obj[key]); // 복사하려는 값이 object 타입이면 함수를 반복해 새로운 오브젝트를 반환
      } else {
          res[key] = origin[key];
      }
    }

    return res;
}

let copy = copyObj(origin);

copy.b.c = 3
console.log(origin.b.c === copy.b.c); // false

 

얕은 복사 & 깊은 복사 : 언제 사용할까?

얕은 복사

  • 객체나 배열이 간단하고, 원시 데이터만 복사하면 될 때
  • 성능이 중요한 경우 (깊은 복사는 비용이 더 크다)
  • 예: 사용자 정보에서 단순한 속성들만 복사하고, 내부 구조가 변경되지 않는 경우

깊은 복사

 

  • 중첩된 참조형 데이터가 포함되어 있고, 독립적인 복사가 필요한 경우
  • 복사한 객체의 모든 속성이 원본과 독립적으로 변경되어야 할 때
  • 예: 복잡한 상태 객체를 복사하여 상태 관리할 때, 변경이 원본에 영향을 미치지 않는 경우

 

얕은 복사의 문제점

얕은 복사는 성능 면에서 효율적이지만, 참조형 데이터가 있을 경우 복사된 객체의 변경에 의해 의도하지 않게 원본 데이터가 변경되는 위험이 있습니다. 특히, 데이터의 구조가 깊거나 복잡할 때, 이러한 문제는 버그로 이어질 수 있습니다.

 

 

 

 

자바스크립트spread 구문은 편리하고 강력한 도구이지만, 얕은 복사만 수행된다는 점을 항상 염두에 두어야 합니다. 단순한 데이터 구조에서는 얕은 복사가 충분하지만, 중첩된 객체나 배열이 있는 복잡한 구조에서는 깊은 복사가 필요할 수 있습니다. 상황에 맞는 복사 방식을 선택하여 코드의 안정성과 성능을 모두 챙기세요!

 

  • 얕은 복사: 객체나 배열의 원시형 데이터만 복사. 참조형 데이터는 공유됨.
  • 깊은 복사: 중첩된 데이터까지 모두 독립적으로 복사.
  • spread 구문은 얕은 복사를 수행하므로, 깊은 복사가 필요한 경우 JSON, Lodash 같은 다른 방법을 사용해야 합니다.

 

 

 

추천글

 

2024.09.12 - [개발 공부 일지/JavaScript] - [JS] 자바스크립트의 자료형

 

[JS] 자바스크립트의 자료형

안녕하세요! 이번 포스팅에서는 자바스크립트(JavaScript)에서 다루는 자료형에 대해 다뤄 볼게요. 자바스크립트는 동적이고 느슨한 타입의 언어라서 변수에 어떤 값이 들어오느냐에 따라 자료형

dev-hpk.tistory.com

2024.09.14 - [개발 공부 일지/JavaScript] - [JS] 자바스크립트의 배열

 

[JS] 자바스크립트의 배열

JavaScript에서 배열(Array)은 데이터를 순서대로 저장하는 데 사용되는 매우 중요한 자료형 중 하나입니다. 배열은 숫자, 문자열, 객체 등 다양한 타입의 데이터를 저장할 수 있으며, 이를 다루기 위

dev-hpk.tistory.com