[JS] Shallow Copy, Deep Copy

중중·2023년 4월 20일

JS 개념 공부

목록 보기
4/4

🚨제가 이해해서 정리한 것은 틀릴 수 있단 걸 알기에 잘못된 부분 제보나 덧붙일 설명, 의견 공유는 언제나 환영합니다!

Shallow Copy, Deep Copy 란?

객체나 배열을 복사할 때 어떻게 복사되는지에 대한 방식

  • Shallow Copy

    객체나 배열을 복사할 때 메모리 주소 값을 복사해 복사본이 원본과 같은 값을 참조하게 된다.

	const car = {
      name : "BMW",
      color : "Silver"
    };
    
    const redCar = car;
    redCar.color = "Red";

	console.log(car); // {name: 'BMW', color: 'Red'}
	console.log(redCar); // {name: 'BMW', color: 'Red'}
  • 장점

    값을 복사하지 않고 참조하므로 빠르고 간결하다.
  • 단점

    같은 값을 참조하기 때문에 원본 객체 또는 복사본을 수정하면 둘 다 수정된다.
  • Deep Copy

    객체나 배열을 복사할 때 내부 값 자체를 완전히 복사해 복사본이 원본과는 독립적이다.

	const car = {
      name : "BMW",
      color : "Silver"
    };
    
    const redCar = {...car};
    redCar.color = "Red";

	console.log(car); // {name: 'BMW', color: 'Silver'}
	console.log(redCar); // {name: 'BMW', color: 'Red'}
  • 장점

    복사본이 원본과 독립적이기 때문에 서로 변경되어도 영향을 주지 않는다.
  • 단점

    내부 값 자체를 복사하기 때문에 복잡한 객체를 복사할 때 느리고 복잡하다.

앞서 공부했던 Call by Value, Call by Reference 와 유사하지만 Call by Value 와 Call by Reference 는 함수 호출 시 인자로 전달되는 값에 대한 전달 방식을 의미하며 Shallow Copy 와 Deep Copy는 객체나 배열을 복사할 때의 복사 방식을 의미하므로 둘은 서로 다른 개념이지만 객체나 배열을 복사할 때 전달하는 인자의 값 복사 방식과 유사한 부분이 있기 때문에 혼동되기 쉬운 점이 있다.

전개 연산자를 이용하면 Deep Copy 일까?

그렇지 않다. 위에서 전개 연산자를 통해 Deep Copy 를 한 것처럼 보이지만 사실 전개 연산자는 기본적으로 Shallow Copy 를 한다. 아래의 코드를 살펴보자.

const person = {
  name: "John",
  age: 30,
  address: {
    street: "123 Main St",
    zip: "12345"
  }
};

const personCopy = {...person};

personCopy.name= "Michael";
personCopy.address.zip = "67891";

console.log(person.name); // "John"
console.log(personCopy.name); // "Michael"

console.log(person.address); // {street: '123 Main St', zip: '67891'}
console.log(personCopy.address); // {street: '123 Main St', zip: '67891'}

전개 연산자를 이용해 복사 했음에도 2 depth level 에 있는 address 는 Shallow Copy 가 되었다. 그 이유는 아래와 같다.

객체를 전개하면 name과 age는 원시 값이어서 값에 의한 전달이 일어나고 address 는 참조 값이어서 참조에 의한 전달이 일어난다. 따라서 personCopyperson 을 전개하면 객체 속성 중 name 과 age 는 값 자체를 복사했기 때문에 독립적이지만 address 는 주소 값을 복사해오기 때문에 종속적이다.

그렇다면 위에 Deep Copy 예시에선 전개 연산자가 왜 Deep Copy 인 것처럼 보일까? 그 이유는 내부에 다른 객체가 없고 원시 데이터로만 이루어진 객체를 전개하여 복사한 결과물과 Deep Copy 를 한 결과물은 동일한 결과를 내놓기 때문이다.

따라서 나는 전개 연산자는 기본적으로 Shallow Copy로 작동하지만 경우에 따라 Deep Copy 와 동일한 결과를 내놓을 수 있다고 결론지었다.

그렇다고 전개 연산자는 내부에 다른 객체가 존재하는 2 depth level 이상의 객체 또한 Deep Copy 와 같은 결과를 내놓을 수 없는 것은 아니다. 아래와 같이 2 depth level 이상인 것들도 전개해주면 가능하다.

const personCopy = {...person, address:{...person.address}};

하지만 이러한 방법은 depth level 이 깊어지는 만큼 반복해줘야하며 번거롭기 때문에 depth level 이 깊을 땐 다른 방법을 사용하자.

depth level 이 깊은 객체를 Deep Copy 하기 위한 다른 방법

  • depth level 만큼 재귀적으로 깊은 복사를 수행하는 함수 작성
  • Lodash 라이브러리의 cloneDeep 메서드 사용
  • JSON.stringify 이용해 객체를 JSON 문자열로 변환하고 JSON.parse 로 구문 분석해 생성한 객체를 복사하기
  • 글로범 함수인 structuredClone 을 사용

참고

[javascript] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)
[JavaScript] 얕은 복사(shallow copy) vs 깊은 복사(deep copy)
JS에서 Spread syntax는 shallow copy일까 deep copy 일까

profile
뉴비 개발 공부중

0개의 댓글