JavaScript에서 객체를 복사할 때 얕은 복사(shallow copy)와 깊은 복사(deep copy)의 차이는 매우 중요합니다. 이번 포스트에서는 deepClone 함수를 통해 깊은 복사의 개념과 활용법을 알아봅니다.
deepClone - 깊은 복사 함수
const deepClone = (obj) => {
if (obj === null || typeof obj !== "object") {
return obj;
}
const result = Array.isArray(obj) ? [] : {}
for (let key of Object.keys(obj)) {
result[key] = deepClone(obj[key]);
}
return result;
}
export const makeQueryString = (query) => {
let search =
Object.entries(query)
.map((entry) => entry.join("="))
.join("&") ?? "";
if (search) search = "?" + search;
return search;
};
deepClone 함수는 객체를 완전히 독립적인 복사본으로 만듭니다. 중첩된 객체와 배열도 모두 재귀적으로 복사되어 원본과 완전히 분리됩니다.
얕은 복사 vs 깊은 복사
얕은 복사의 문제점
// 얕은 복사 예시
const original = { a: 1, b: { c: 2 } };
const shallow = Object.assign({}, original);
shallow.b.c = 99;
console.log(original.b.c); // 99 (원본도 변경됨!)
깊은 복사의 해결
// 깊은 복사
const original = { a: 1, b: { c: 2 } };
const deep = deepClone(original);
deep.b.c = 99;
console.log(original.b.c); // 2 (원본은 변경되지 않음)
기본 사용법
// 객체 복사
const original = { a: 1, b: { c: 2 }, d: [3, 4] };
const cloned = deepClone(original);
cloned.b.c = 99;
cloned.d.push(5);
console.log(original.b.c); // 2 (변경되지 않음)
console.log(original.d); // [3, 4] (변경되지 않음)
console.log(cloned.d); // [3, 4, 5]
배열 복사
// 배열 복사
const arr = [{ x: 1 }, { y: 2 }];
const clonedArr = deepClone(arr);
clonedArr[0].x = 99;
console.log(arr[0].x); // 1 (원본은 변경되지 않음)
중첩 객체 복사
// 깊게 중첩된 객체
const complex = {
user: {
name: '홍길동',
address: {
city: '서울',
district: '강남구'
},
hobbies: ['독서', '영화']
},
settings: {
theme: 'dark',
language: 'ko'
}
};
const cloned = deepClone(complex);
cloned.user.address.city = '부산';
cloned.user.hobbies.push('음악');
console.log(complex.user.address.city); // "서울" (변경되지 않음)
console.log(complex.user.hobbies); // ["독서", "영화"] (변경되지 않음)
실전 활용 예시
1. 폼 데이터 초기화
// 폼의 초기값 저장
const initialFormData = {
name: '',
email: '',
address: {
city: '',
zipcode: ''
}
};
// 사용자가 입력한 데이터
let formData = deepClone(initialFormData);
formData.name = '홍길동';
formData.address.city = '서울';
// 리셋 버튼 클릭 시
const handleReset = () => {
formData = deepClone(initialFormData); // 깨끗한 초기값으로 복원
};
2. 상태 관리 (Redux, Vuex 등)
// Redux reducer에서
const reducer = (state, action) => {
switch(action.type) {
case 'UPDATE_USER':
// 깊은 복사로 새 상태 생성
const newState = deepClone(state);
newState.user.name = action.payload.name;
return newState;
default:
return state;
}
};
3. 그리드 데이터 편집
// 그리드에서 행 편집 시작 시
const startEdit = (rowKey) => {
const originalRow = grid.getRow(rowKey);
const editingRow = deepClone(originalRow);
// 편집 중인 데이터 (원본과 분리)
editingRow.name = '수정된 이름';
// 취소 시 원본으로 복원
const cancelEdit = () => {
grid.setRow(rowKey, originalRow);
};
// 저장 시에만 원본 업데이트
const saveEdit = () => {
grid.setRow(rowKey, editingRow);
};
};
4. 설정 복사 및 비교
// 사용자 설정 관리
const defaultSettings = {
theme: 'light',
language: 'ko',
notifications: {
email: true,
push: false
}
};
// 사용자 설정 복사
const userSettings = deepClone(defaultSettings);
userSettings.theme = 'dark';
// 변경사항 확인
const hasChanges = JSON.stringify(defaultSettings) !== JSON.stringify(userSettings);
5. 데이터 백업 및 복원
// 데이터 백업
let backup = null;
const backupData = (data) => {
backup = deepClone(data);
};
const restoreData = () => {
if (backup) {
return deepClone(backup);
}
return null;
};
// 사용 예시
const currentData = { items: [1, 2, 3] };
backupData(currentData);
currentData.items.push(4);
// 백업으로 복원
const restored = restoreData();
console.log(restored.items); // [1, 2, 3] (4가 없음)
6. 객체 병합 (Merge)
// 깊은 병합 함수
const deepMerge = (target, source) => {
const cloned = deepClone(target);
for (let key in source) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
cloned[key] = deepMerge(cloned[key] || {}, source[key]);
} else {
cloned[key] = source[key];
}
}
return cloned;
};
// 사용 예시
const base = {
user: { name: '홍길동', age: 30 },
settings: { theme: 'light' }
};
const update = {
user: { age: 31 },
settings: { language: 'ko' }
};
const merged = deepMerge(base, update);
// { user: { name: '홍길동', age: 31 }, settings: { theme: 'light', language: 'ko' } }
7. 데이터 검증 전 복사
// 검증 전 데이터 복사
const validateAndSave = (data) => {
const cloned = deepClone(data);
// 검증 로직 (원본 데이터는 안전)
if (!cloned.name) {
throw new Error('이름이 필요합니다');
}
// 검증 통과 시 저장
saveToDatabase(cloned);
};
성능 고려사항
1. 큰 객체 복사 시 주의
// 매우 큰 객체는 깊은 복사가 느릴 수 있음
const largeObject = { /* 수만 개의 속성 */ };
// 필요시 선택적 복사
const selectiveClone = (obj, keys) => {
const cloned = {};
keys.forEach(key => {
if (obj[key] && typeof obj[key] === 'object') {
cloned[key] = deepClone(obj[key]);
} else {
cloned[key] = obj[key];
}
});
return cloned;
};
2. 순환 참조 처리
// 순환 참조가 있는 객체는 deepClone이 무한 루프에 빠질 수 있음
const circular = { a: 1 };
circular.self = circular;
// 순환 참조 감지 필요 시 별도 처리 필요
마무리
deepClone 함수는 JavaScript에서 객체를 안전하게 복사할 때 필수적인 유틸리티입니다. 특히 상태 관리, 폼 처리, 데이터 편집 등에서 원본 데이터를 보호하면서 작업할 수 있게 해줍니다.
'프론트' 카테고리의 다른 글
| 타입스크립트를 사용하는 이유 (0) | 2026.04.11 |
|---|---|
| JavaScript 한국어 조사 자동 선택 함수 (0) | 2026.02.10 |
| JavaScript 숫자 포맷팅 (0) | 2026.02.06 |
| JavaScript 날짜/시간 처리 함수 (0) | 2026.02.06 |
| Swiper Bullets를 바(Bar) 형태로 변경하기 (0) | 2025.12.17 |