본문 바로가기

JavaScript

JavaScript - 얕은 복사, 깊은 복사

객체 또는 배열을 복사하는 두 가지 방법의 차이점에 대한 설명.

두 방법은 복사된 결과의 구조와 원본 객체 간의 관계를 다르게 다룬다.

 

1. 얕은 복사

  • 복사본의 속성이 원본객체와 같은 참조를 공유한다.
  • 둘 중 한쪽을 변경할 경우 나머지도 똑같이 변경된다.
  • 내부 객체나 배열은 참조로 복사된다. = 내부 객체나 배열은 실제 값이 아닌 메모리 주소로 복사된다.
    - 따라서 원본 객체와 복사본 객체는 내부 객체에 대한 동일한 참조를 공유한다.
  • 속성이 모두 원시 값인 객체의 복사는 얕은 복사, 깊은복사 모두의 정의에 부합하다.
  • 중첩된 객체의 값이 아닌 최상위 속성만 복사한다.
    - 따라서 복사본의 최상위 속성을 재할당해도 원본객체에 영향을 끼치지 않는다.
    - 복사본의 중첩 객체 속성을 재할당하면 원본 객체에 영향을 끼친다.
  •  javaScript에서 모든 표준 내장 객체의 복사 작업은 깊은 복사가 아닌 얕은 복사본을 생성하는 것이다.

예시

원본 객체 a 와 얕은 복사를 수행한 b객체가 있을 경우.

  • 두 객체는 같은 객체가 아니다.( a !== b)
  • a와 b의 속성은 같은 이름과 순서이다.
  • 두 객체의 속성 값은 동일하다.
  • 두 객체의 프로토타입 체인은 동일하다.
  • b의 중첩된 속성인 list를 변경하면 a의 list도 변경되어있다.
const a = ["noodles", { list: ["eggs", "flour", "water"] }];
const b = Array.from(a);
b[1].list = ["rice flour", "water"];

a[1].list // [ "rice flour", "water" ]
  • b의 최상위 속성값을 재할당한경우, b에서만 변경된다.
b[0] = "rice noodles";

a[0] // noodles
JSON.stringify(b) // ["rice noodles",{"list":["rice flour","water"]}]
JSON.stringify(a) // ["noodles",{"list":["rice flour","water"]}]

복사 방법

  • Array.prototype.concat()
  • Array.prototype.slice()
  • Array.from()
  • Object.assign()
  • Object.create()
  • 스프레드연산자( ... )
const a = ["noodles", { list: ["eggs", "flour", "water"] }];
const b = [...a];

2. 깊은 복사

  • 복사본의 속성이 원본객체와 같은 참조를 공유하지 않는다.
  • 결과적으로 원본 객체와 복사본 객체는 완전히 분리되어있으며 어떤 변경도 서로에게 영향을 주지 않는다.

예시

원본 객체 a 와 깊은 복사를 수행한 b객체가 있을 경우.

  • 두 객체는 같은 객체가 아니다.
  • a와 b의 속성은 같은 이름과 순서이다.
  • 두 객체의 속성 값은 구조적으로 동일하다.
  • 두 객체의 프로토타입 체인은 구조적으로 동일하다.
  • 프로토타입체인을 복사할 수도 있고 복사하지 않을 수도 있다.
    - 하지만 구조적으로 동일하지 않은 프로토타입 체인을 가진 두 객체(예를들어 하나는 배열, 하나는 객체)는 서로의 복사본이 아니다.
  • b의 속성을 변경할 경우 a는 변경되지 않는다.
const a = ["noodles", { list: ["eggs", "flour", "water"] }];
const b = JSON.parse(JSON.stringify(a));
b[1].list = ["rice flour", "water"];

a[1].list // [ "eggs", "flour", "water" ]

복사 방법

  • 외부라이브러리 사용(ex) Lodash의 _.cloneDeep())
  • JSON.stringify() + JSON.parse()
    함수, 심볼등의 복잡한 객체는 stringify() 를 실행할 수 없기때문에 깊은 복사본을 만들 수 없다.

 

 

참조

https://developer.mozilla.org/ko/docs/Glossary/Shallow_copy

https://developer.mozilla.org/ko/docs/Glossary/Deep_copy