본문 바로가기
Frontend2026년 6월 28일4분 읽기

얕은 복사 vs 깊은 복사 — JavaScript 객체가 꼬이는 이유

YS
김영삼
조회 688
얕은 복사 vs 깊은 복사 — JavaScript 객체가 꼬이는 이유

핵심 요약

JavaScript는 객체·배열을 참조로 다룬다. {...obj}Object.assign얕은 복사라 1단계 속성만 복제하고, 중첩된 객체는 여전히 같은 참조를 공유한다. 그래서 복사본의 a.b.c를 바꾸면 원본도 바뀐다. 완전히 분리하려면 깊은 복사(structuredClone 등)가 필요하다.

1. 왜 원본이 같이 바뀌나

const a = { user: { name: '철수' } }
const b = { ...a }          // 얕은 복사
b.user.name = '영희'
console.log(a.user.name)    // '영희' 😱 원본도 바뀜

{...a}user가 가리키는 참조만 복사했다. a.user와 b.user는 같은 객체다.

2. 얕은 복사 방법들

  • { ...obj }, Object.assign({}, obj)
  • 배열은 [...arr], arr.slice(), Array.from(arr)
  • 공통점: 1단계만 복사. 중첩은 공유

3. 깊은 복사 방법

방법특징
structuredClone(obj)표준·권장. Date·Map·Set도 복제, 순환참조 OK
JSON.parse(JSON.stringify(obj))간단하지만 함수·undefined·Date 손실
lodash cloneDeep엣지케이스까지 견고, 의존성 추가

4. React에서 특히 중요한 이유

// ❌ 원본 배열을 직접 변경 → 리렌더 안 됨
state.items.push(x); setState(state)

// ✅ 새 참조를 만들어 불변 업데이트
setState({ ...state, items: [...state.items, x] })

React는 참조 비교로 변경을 감지한다. 원본을 mutate하면 참조가 그대로라 렌더가 안 일어난다.

5. 함정

  • JSON.stringify 복사는 undefined·함수·Symbol을 날리고 Date를 문자열로 만든다
  • 중첩이 깊으면 필요한 부분만 새로 만드는 게 성능상 낫다(전체 깊은 복사는 비쌈)

자주 묻는 질문

structuredClone과 JSON 방식 중 뭘 써야 하나요?

브라우저·Node 최신 환경이면 structuredClone이 표준이고 Date·Map·Set·순환참조까지 처리해 더 안전합니다. 순수 데이터(문자·숫자·배열·평범한 객체)만 있고 구형 환경을 지원해야 하면 JSON 방식도 무방합니다.

깊은 복사는 항상 하는 게 안전하지 않나요?

안전하지만 비쌉니다. 큰 객체를 매번 통째로 복제하면 성능·메모리 부담이 큽니다. 실무에선 변경되는 경로만 새로 만드는 불변 업데이트(스프레드 중첩)로 필요한 부분만 복사합니다.

const로 선언하면 객체가 안 바뀌지 않나요?

const는 변수 재할당만 막습니다. 객체 내부 속성은 그대로 바꿀 수 있습니다. 내용까지 얼리려면 Object.freeze가 필요하지만 이것도 얕게만 얼립니다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록