072DATA

얕은 복사와 깊은 복사 - JavaScript 본문

FrontEnd/HTML, CSS, JavaScript

얕은 복사와 깊은 복사 - JavaScript

0720 2024. 7. 30. 22:31

시작하기전 

 

 

 

시작하기에 앞서 솔직히 두 복사를 알기 위해 공부해야할 사항이 많습니다.

메모리에 대한 지식이나, 원시 타입참조 타입 그리고 객체란 무엇인지 등

 

이러한 여러가지 개념들에 대해서 이해하고 있지 않다면

나처럼 오랜 시간을 붙들고 있어야 할 것이며 본다고 이해가 잘 되지 않을 겁니다.

 

그리하여 메모리 개념데이터 타입에 대해 공부를 한 뒤에

얕은 복사와 깊은 복사에 대한 지식을 습득하길 권장합니다.

 

글의 순서로는 얕은 복사, 깊은 복사 그리고

두 복사의 필요성에 대해서는 짧게 작성해 보겠습니다.

 

 

 

얕은 복사 (Shallow Copy)

 

 

 

 

 

얕은 복사는 객체를 복사할 때, 그 객체 안에 있는 직접적인 속성들만 복사합니다.

하지만 그 속성들이 또 다른 객체를 가리키고 있으면,

그 또 다른 객체는 복사되지 않고 그냥 *참조(메모리 주소)만 복사됩니다.

 

참조(Reference): 변수에 저장된 객체나 배열이 실제 데이터가 저장된 메모리 위치를 가리키는 방식.

 

 

얕은 복사 예시

const original = {
  name: "John",
  address: {
    city: "New York"
  }
};

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

shallowCopy.name = "Jane";
shallowCopy.address.city = "San Francisco";

console.log(original.name); // John (영향 없음)
console.log(shallowCopy.name); // Jane
console.log(original.address.city); // San Francisco (영향 있음)
console.log(shallowCopy.address.city); // San Francisco

 

 

 

 

얕은 복사에서 원시 타입(문자열, 숫자, 불리언 등)은 항상 값 그 자체로 복사되기 때문에

코드 예시에서 original.name의 복사 값은 문자열 "John"으로 복사 되지만

 

original.address는 원시 타입이 아닌 참조 타입객체이기 때문에 

메모리 주소를 복사하여 값을 할당 합니다 

 

그렇기 때문에 새롭게 복사된 객체 shallowCopy의 name을 Jane으로 변경해도

원본 객체인 original.name에는 영향이 없지만

 

original.address의 속성은 참조 타입으로 메모리 주소 자체를 복사하였기 때문에

복사된 객체인 shallowCopy의 address.city를 변경하게 될 경우 

원본 객체인 original.address에도 영향을 미치는 겁니다.

 

 

 

깊은 복사 (Deep Copy)

 

 

 

 

깊은 복사는 객체의 모든 수준을 *재귀적으로 복사하여,

원본 객체와는 독립적인 복사본을 만듭니다.

 

재귀적이라는 것은 "스스로 복사한다"라는 의미를 갖는데

이는 프로그래밍에서 함수가 자기 자신을 호출하는 것을 의미합니다

그러나 깊은 복사에서는 재귀적이라는 의미가 다르게 적용되며

객체의 모든 속성 하나하나 검사해서 그 속성들이 객체라면

그 객체들 역시 다시 깊은 복사를 수행한다는 뜻입니다.

 

 

 

깊은 복사 예시

function deepCopy(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj; // 원시 타입은 직접 반환
  }

  if (Array.isArray(obj)) {
    return obj.map(item => deepCopy(item)); // 배열일 경우 각 요소를 재귀 복사
  }

  const newObj = {};
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepCopy(obj[key]); // 객체일 경우 각 속성을 재귀 복사
    }
  }
  return newObj;
}

const original = {
  name: "John",
  address: {
    city: "New York",
    details: {
      street: "5th Avenue",
      number: 123
    }
  }
};

// 깊은 복사
const deepCopy = deepCopy(original);

// 변경
deepCopy.address.city = "San Francisco";

console.log(original.address.city); // New York
console.log(deepCopy.address.city); // San Francisco

 

 

 

위 예시 코드처럼 깊은 복사 코드를 만들어서 원시타입일 경우 값을 그대로 반환하고

배열객체일 경우에 *재귀 복사, 즉 그 속에 있는 속성들을

*모두 다시 하나하나 검사하여 객체나 배열이 있으면 또 재귀 복사를 하도록 합니다.

 

이렇게 직접 구현하게 되면 필요한 부분에 맞춰서 복사를 수행할 수 있습니다.

 

이 외에도 깊은 복사로 JSON.parse(JSON.stringify(original)) 을 사용하는 방법이나

라이브러리, structuredClone() 함수를 사용하는 방법이 있습니다.

 

얕은 복사와 깊은 복사의 필요성

 

 

 

 

공부하면서 이해한 바로  각각 한줄로 요약하자면 

얕은 복사에 경우 원시 타입의 속성들만 복사하여 가져올 때 사용하고

깊은 복사는 독립적인 복사본을 필요로 하고 객체나 배열까지도 데이터 변경이

원본과 복사본에 서로 영향을 미치지 않도록 해야 한다면 사용한다고 볼 수 있습니다.

 

또한 아주 많은 양속성들을 복사해야 한다면  얕은 복사나 깊은 복사를

*for... in 구문과 함께 사용하여 하드 코드를 방지하고 효율적인 코드를 만들어 낼 수 있습니다. 

 

for...in : 객체의 모든 열거 가능한 속성을 순회하며, 속성 이름을 얻고 각 속성의 값을 처리할 수 있습니다

 

 

 

마무리

 

 

오늘은 얕은 복사와 깊은 복사에 대해서 정리해 봤는데

이해하기까지 꽤나 오랜 시간이 걸렸기 때문에

 

모든 정리가 마무리 되고 나서 매우 달콤했다

요즘 강의를 들으면서 너무 어려운 개념도 많고

 

공부해야할 범위가 넓어서 시간도 오래 걸리고

점차 앞으로 나아가기가 쉽지 않다 그럴때마다 힘들고

 

현타가 오는데 오늘처럼 이렇게 한 개념에 대해서

이해하고 나면 정말 속이 뻥 뚫린다.. 내일도 화이팅