본문 바로가기
IT/개발

[JS] 깊은 복사와 얕은 복사

by aloveu 2024. 4. 10.
반응형

안녕하세요! aloveu입니다.

많은 주니어 개발자들을 겪으면서  기초적이지만  실무에서 모르면 안 되는 스크립트들을 정리해야겠다는 생각을 하고 포스팅을 하려고 합니다.

 

Javascript에서 객체와 배열을 다룰 때, 가장 중요한 개념 중 하나가 바로 '복사'인데요.

오늘 포스팅은 저도 가끔 용어가 헷갈리는 깊은 복사얕은 복사입니다.


| 깊은 복사 (Deep Copy)

깊은 복사는 원본 객체나 배열을 새로운 메모리 공간에 복사하는 방식입니다.

이게 쉬운말로는 그냥 구조만 복사하고 서로 연관되지 않는 거예요. 그래서 복사본 중에 하나의 속성을 변경해도 다른 복사본의 속성은 변경이 되지 않습니다. 

위에서 용어가 헷갈린다고 했는데 깊은복사가 왠지 서로 더 연관 있어 보여서 원본을 바꿔도 사본이 변경될 거 같은 느낌 때문이에요. 이건 저만의 생각일 수는 있어요 ㅋㅋㅋㅋ

 

JSON.parse(JSON.stringify(Obj));

깊은 복사의 방법으로는 JSON.stringify를 한 후에 다시 parse를 하는 고전적인 방법이 있습니다.

const originalObj = {
  name: 'John',
  age: 30,
  address: {
    city: 'New York',
    country: 'USA'
  }
};

const deepCopy = JSON.parse(JSON.stringify(originalObj));
deepCopy.address.city = 'Los Angeles';
console.log(originalObj.address.city);

 

이렇게 복사한 deepCopy의 address를 수정하면 원본의 city는 어떻게 될까요?

깊은 복사는 원본이 변하지 않아 'New York'이 콘솔에 찍히게 됩니다.

 

structuredClone();

ECMAScript 2021(ES12)에서 도입된 새로운 API입니다. 이 함수는 객체, 배열, 기본 데이터 타입 등 다양한 데이터 구조를 깊은 복사할 수 있게 도와줘요.

위의 고전방식보다 성능이 좋고 날짜, 정규표현식과 같은 non-serializable데이터도 깊은 복사 할 수 있습니다.

const deepCopy = structuredClone(originalObj);

 

이거 실무에서 많이 쓰게 될겁니다. 쓰기 좋거든요 ㅎ

하지만 단점도 있어요.

  • 일단 Function은 복제할 수 없습니다. DataCloneError를 뱉습니다.
  • DOM 노드는 복제할 수 없습니다. DataCloneError를 뱉습니다.
  • 특정 개체 속성은 유지 되지 않습니다. (setter, getter, prototype, RegExp개체의 lastIndex속성..)

 

| 얕은 복사 (Shallow Copy)

얕은 복사는 참조 복사입니다. 같은 메모리 공간을 사용하고 지칭하는 변수만 다른 거예요.

따라서 복사본 중 하나의 속성을 변경하면, 다른 복사본이나 심지어 원본까지 해당 속성이 변경됩니다. 

그래서 조심히 써야 합니다.

 

전개연산자 (Spread Operator)

const shallowCopy = { ...originalObj };
shallowCopy.address.city = 'Los Angeles';
console.log(originalObj.address.city);

 

여기서 originalObj.address.city 값은 어떤 걸로 찍힐까요? 'Los Angeles'로 찍힙니다.

Object.assign()

const shallowCopy = Object.assign({}, originalObj);

 

Array.slice(), Array.concat()

배열의 slice와 concat메서드는 기존 배열의 얕은 복사본을 생성합니다.

이때 배열요소가 객체인 경우에 객체에 대한 참조만 복사가 됩니다.

const originalArray = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 25 }
];

const shallowCopy = originalArray.slice();
shallowCopy[0].name = 'Bob';

console.log(originalArray[0].name); // 출력: 'Bob'
console.log(shallowCopy[0].name); // 출력: 'Bob'

 

| 결론

그래서 결론은 어떤 객체를 복사할 때 꼭 이게 깊은 복사(구조)인지 얕은 복사(참조)인지 정확히 알고 적절한 복사 방식을 선택해야 나중에 예상치 못한 코드 동작을 방지 할 수 있어요.

이런 기본적인 것 때문에 몇 시간씩 디버깅하고 있지 말자고요.

 

그럼 즐코딩하세요. ^___^

 

| 참조

https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

반응형