Adventure Time - Finn 3
본문 바로가기
프론트

JavaScript 유틸리티 함수 - deepClone

by hyun9_9 2026. 2. 9.

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에서 객체를 안전하게 복사할 때 필수적인 유틸리티입니다. 특히 상태 관리, 폼 처리, 데이터 편집 등에서 원본 데이터를 보호하면서 작업할 수 있게 해줍니다.