javascript deep copy 실무 가이드: 개념·예제·주의점
javascript deep copy를 실무에서 정확히 이해하고 적용하는 방법을 단계별로 정리합니다. 개념, 코드 예제, 비교표, 체크리스트와 성능·보안 주의점을 포함해 바로 쓸 수 있도록 구성했습니다.
javascript deep copy이 필요한 상황
javascript deep copy는 객체나 배열의 중첩된 값을 원본에 영향을 주지 않고 복제해야 할 때 필수입니다. 이 글에서는 javascript deep copy의 개념, 주요 방법(structuredClone, JSON 방법, lodash 등), 실무 코드 예제, 비교표, 체크리스트, 성능·보안·운영 관점의 주의점까지 다룹니다. 독자는 어떤 방법을 선택해야 하는지 판단하고 바로 적용할 수 있습니다.
javascript deep copy 핵심 개념
깊은 복사(deep copy)란 복제된 객체 내부의 모든 중첩 객체까지 새 인스턴스로 복사하는 것을 뜻합니다. 얕은 복사(shallow copy)는 최상위 속성만 복사하고 중첩된 객체는 원본과 참조를 공유합니다. 자바스크립트에서 값 타입(원시값)은 기본적으로 복사되지만 객체, 배열, 함수 등 참조 타입은 복사 방식에 따라 원본을 변경할 수 있습니다.
핵심 포인트:
- 참조 공유로 인한 부작용 방지
- 순환(circular reference) 처리 필요 여부
- 함수, Symbol, Date, RegExp, Map/Set 등 비원시 타입 처리 방법
javascript deep copy 실무 예제
아래 예제는 다양한 방법을 보여줍니다: JSON 방법, structuredClone, lodash cloneDeep, 수동 구현(재귀) 예시.
// 예제 입력 데이터 const obj = { a: 1, b: { c: 2 }, d: [3, { e: 4 }], f: new Date('2020-01-01'), }; // 1) JSON stringify/parse (단순, 함수/undefined/Date/Map/Set/순환 미지원) const jsonCopy = JSON.parse(JSON.stringify(obj)); // 2) structuredClone (현대 브라우저/Node 17+ 지원) // 브라우저: structuredClone(obj) // Node.js: globalThis.structuredClone(obj) 또는 util의 structuredClone const structuredCopy = structuredClone(obj); // 3) lodash cloneDeep 사용 // import { cloneDeep } from 'lodash'; // const lodashCopy = cloneDeep(obj); // 4) 재귀 수동 복사 (순환 참조 처리 필요) function deepClone(value, map = new WeakMap()) { if (value === null || typeof value !== 'object') return value; if (map.has(value)) return map.get(value); if (value instanceof Date) return new Date(value); if (value instanceof RegExp) return new RegExp(value); if (Array.isArray(value)) { const arr = []; map.set(value, arr); for (const v of value) arr.push(deepClone(v, map)); return arr; } const result = {}; map.set(value, result); for (const key of Object.keys(value)) { result[key] = deepClone(value[key], map); } return result; } const manualCopy = deepClone(obj); console.log(jsonCopy, structuredCopy, manualCopy);
방법별 비교표
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | JSON stringify/parse | structuredClone | lodash cloneDeep |
| 내용 | 간단, 속도가 빠름(단순 구조) | 표준, 순환 지원, 대부분 타입 지원 | 널리사용, 다양한 타입 지원, 안정적 |
| 내용 | Date/RegExp/Map 등 비지원, 순환 에러 | 브라우저/Node 버전 제한 | 번들 크기 증가 가능 |
언제 쓰면 좋고 언제 피해야 할까
-
언제 쓰면 좋은가:
- 상태 관리에서 불변성 유지가 필요할 때
- API 응답을 가공하기 전에 원본을 보호해야 할 때
- 테스트에서 의도치 않은 사이드 이펙트를 방지할 때
-
언제 피해야 하는가:
- 매우 큰 객체(수십 MB 이상)를 자주 복사해야 할 때(비용 큼)
- 함수/클로저 내부 상태를 그대로 복제해야 할 때
- 순환 참조가 있고 간단한 문자열 변환 방식으로는 표현할 수 없을 때
실무 체크리스트
- 복사할 데이터의 타입을 확인했는가? (Date, RegExp, Map/Set 등)
- 순환 참조가 있는가? structuredClone 또는 순환 처리 로직이 필요한가?
- 성능 민감 경로(랜더링 루프, 대량 처리)에서 복사 빈도를 줄였는가?
- 외부 라이브러리(lodash) 도입 시 번들 영향과 버전 호환을 검토했는가?
- 보안상 민감한 내용(토큰 등)을 복사해 클라이언트에 노출하지 않는가?
성능·보안·운영 주의점
성능:
- JSON 방법은 단순 구조에서 빠르지만, 중첩이 깊거나 큰 데이터에서 메모리와 CPU 비용이 큽니다.
- structuredClone는 브라우저/Node 구현에 따라 최적화되어 있고 순환 참조도 처리하지만, 지원 범위를 확인해야 합니다.
- lodash cloneDeep은 신뢰성이 높지만 대량 데이터에서 비용이 발생합니다. 필요할 때만 사용하세요.
보안:
- 객체 내 민감한 값(예: 토큰, 비밀번호)을 불필요하게 복제하여 로그/전송하지 않도록 주의합니다.
- 외부 입력을 복사할 때 prototype pollution 공격 가능성을 고려해 안전한 복제가 필요합니다.
운영:
- Node 버전이나 브라우저 지원을 기준으로 구현 전략을 정하세요. structuredClone가 없으면 폴리필 또는 라이브러리를 고려합니다.
- 서버 측에서 대량 복제가 필요하면 스트리밍 변환이나 부분 복사 전략(필요 필드만 복사)을 사용하세요.
javascript deep copy 구현 판단 기준
| 구분 | 항목1 | 항목2 | 항목3 |
|---|---|---|---|
| 내용 | 단순 데이터 | 중첩/순환 필요 | 특수 타입(Date/Map 등) |
| 내용 | JSON 방법 가능 | structuredClone 또는 재귀 필요 | lodash or 커스텀 로직 권장 |
자주 묻는 질문
Q1: JSON stringify/parse로 항상 복제해도 되나요? A1: 아니요. JSON 방식은 함수, undefined, Symbol, Date, Map/Set, 순환 참조를 지원하지 않습니다. 데이터 구조가 단순한 경우에만 사용하세요.
Q2: structuredClone와 lodash cloneDeep 중 무엇을 선택해야 하나요? A2: 브라우저/Node 환경에서 structuredClone을 사용할 수 있으면 우선 고려하세요(순환 지원, 성능 이점). 지원하지 않으면 lodash cloneDeep 또는 신뢰할 수 있는 재귀 구현을 사용하세요.
Q3: 순환 참조가 있는 데이터를 복사하려면 어떻게 해야 하나요? A3: structuredClone은 순환을 자동으로 처리합니다. 수동 구현 시 WeakMap을 사용해 방문 노드를 추적하고 순환 참조를 복원해야 합니다.
Q4: 복사 성능 최적화 팁이 있나요? A4: 불필요한 전체 복사를 피하고 필요한 필드만 복사하거나 구조 분해로 얕은 복사를 활용하세요. 빈번한 복사는 메모리 할당을 증가시키므로 캐시나 변경점(diff) 적용 방법을 검토하세요.
정리
- javascript deep copy는 참조 공유로 인한 사이드 이펙트를 방지하기 위해 필요하다.
- 방법별 장단점: JSON(간단하지만 제한적), structuredClone(표준적이고 순환 지원), lodash cloneDeep(광범위 타입 지원).
- 실무에서는 데이터 타입, 순환 여부, 성능 요구를 기반으로 방법을 선택하라.
- 체크리스트와 예제 코드를 통해 바로 적용할 수 있다.