[자바스크립트] 얕은복사, 깊은복사

박은정·2021년 11월 10일
1

자바스크립트

목록 보기
14/25
post-thumbnail

얕은 복사와 깊은 복사

얕은 복사와 깊은 복사의 개념

설명

자바스크립트에서의 데이터는 기본형과 참조형 데이터로 나눠져있는데 데이터를 할당할 경우, 기본형 데이터는 값이 담긴 주솟값을 바로 복사를 하지만, 참조형 데이터는 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제하게 된다.

데이터를 복사하게 되면 기본형 데이터는 동일한 메모리를 할당하게 되더라도, 이후에 다른 값으로 변경하게 되면 새로운 메모리에 값을 할당하기 때문에 서로에게 영향을 미치지 않게 되지만, 참조형 데이터의 경우, 변수가 객체의 주소를 가리키는 값이기 때문에 복사된 값인 주소가 동일한 값을 가리킨다. 이러한 객체의 특성 때문에 객체를 복사하는 방법은 크게 두 가지로 나뉜다.

얕은 복사 shallow copy 란 객체를 복사할 때 원래의 값과 복사된 값이 동일한 참조를 하는 것을 말하는데,
만약 객체 안에 객체가 있을 경우 복사된 값 내부의 하나의 객체라도 원본 객체를 참조하고 있다면 이를 얕은 복사라고 한다.
이러한 특성 때문에
깊은 복사deep copy 란 복사된 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 관계를 말한다.

요약

해당 데이터의 직접 속한 프로퍼티를 복사를 하는 얕은복사를 하게 되면, 해당 프로퍼티에 대해 원본과 사본 모두 동일한 참조형 데이터의 주소를 가리키기 때문에 사본과 원본 둘 중 하나의 데이터를 바꾸면 나머지 다른 한쪽도 변경된다.
한편 데이터 내부의 모든 값들을 일일이 찾아서 복사하는 깊은 복사를 하게 되면, 객체 안에 객체가 있는 경우에도 원본과의 참조가 완전히 끊어지게 되어 사본과 원본 둘 중 하나의 데이터를 변경하더라도 영향이 가지 않는다.


얕은 복사와 깊은 복사를 하는 방법

설명

얕은 복사 Shallow Copy 하는 방법

  1. Object.assign() 메서드
    첫 번째 요소로 들어온 객체에 두 번째 인자로 들어온 객체를 복사한다.
const object = {
  a: 1,
  b: { c: 2 }
};

const copyObject = Object.assign({}, object);
copyObject.b.c = 3

object === copyObject // false : 원본과 사본이 동일하지 않다
object.b.c === copyObject.b.c // true : 프로퍼티 내부의 객체는 원본과 사본과의 참조가 끊기지 않았다
  1. 전개 연산자 ...
const object = {
  a: 1,
  b: { c: 2 }
};

const copyObject = {...object}
copyObject.b.c = 3

object === copyObject // false 
object.b.c === copyObject.b.c // true

깊은 복사 Deep Copy 하는 방법

  1. 재귀함수를 이용한 복사
object = {
  a: 1,
  b: { c: 2 }
};

function copyObjectFunction(object) {
  const result = {};

  for (let key in onject) {
    if (typeof object[key] === 'object') result[key] = copyObject(object[key]);
    else result[key] = object[key];
  }
  return result;
}

const copyObject = copyObjectFunction(object);
copyObject.b.c = 3

object.b.c === copyObject.b.c // false : 원본과 사본 프로퍼티 내부의 객체의 참조가 끊어졌다
  1. JSON.stringfy() 메서드

JSON.stringfy() 메서드는 객체를 json 형태의 문자열로 변환하는 방법인데, 이 과정에서 원본 객체와의 참조가 모두 끊어진다.
이러한 이유로 객체를 json 문자열로 변환한 다음에 JSON.parse() 메서드를 이용해 다시 자바스크립트 객체로 만들어주면 깊은 복사가 이루어진다.

const object = {
  a: 1,
  b: { c: 2 }
};

const copyObject = JSON.parse(JSON.stringfy(object));
copyObject.b.c = 3

object.b.c === copyObject.b.c // false
  1. 라이브러리 활용

lodash 라이브러리를 사용해서 깊은 복사를 할 수 있다.

const object = {
  a: 1,
  b: { c: 2 }
};

const copyObject = _.cloneDeep(object);
copyObject.b.c = 3

object.b.c === copyObject.b.c // false

요약

Object.assign() 메서드전개연산자를 활용해서 바로 아래 단계에서만 복사를 하면 얕은복사를 하게 된다.

반면, 해당 프로퍼티가 객체일 때 재귀함수를 이용하거나 JSON.stringfy() 메서드를 이용해 json문자열로 변환하면서 원본 객체와의 참조를 끊은 다음 다시 JSON.parse() 메서드 를 이용해 자바스크립트 객체로 만드는 방법으로 데이터 내부의 모든 값을 복사해서 깊은 복사를 하는 방법이 있다.

이렇게 깊은 복사를 하는 방법이 간단하지 않기 때문에, lodash 같은 라이브러리 를 활용해서 깊은 복사를 더 쉽게 하는 방법도 있다.


Plus

Q. 깊은 복사 json.stringfy() json.parse()를 하는데 이 방법을 하면 어떤게 안가져와지는가?

A. 메서드나 숨겨진 프로퍼티인 __proto__getter/setter 등과 같이 JSON 형태로 변환할 수 없는 프로퍼티는 모두 무시한다.

profile
새로운 것을 도전하고 노력한다

0개의 댓글