[JavaScript] 2차원 이상 객체 깊은 복사 방법

nemo·2022년 5월 25일
3

JavaScript

목록 보기
19/23
  • 얕은 복사 (Shallow copy)
    주소 값을 복사하기 때문에 참조하고 있는 실제 값이 같음
  • 깊은 복사 (Deep copy)
    실제 값을 독립적인 새로운 메모리 공간에 복사, 참조를 공유하지 않음

2차원 이상의 객체 얕은 복사하기

참고로 아래 두 가지 얕은 복사 방식의 경우 1차원 객체일 때에는 깊은 복사된다.

방법 1. Object.assign()

const obj = {
  a: 1,
  b: {
    c: 2,
  }
}

const newObj = Object.assign({}, obj);

// newObj의 값을 변경했을 때
newObj.b.c = 99;

console.log(obj === newObj); // false
console.log(obj.b.c); // 99
console.log(obj.b.c === newObj.b.c); // true

obj === newObjfalse인 것으로 보아 두 객체는 다른 참조 값을 갖는다. 따라서 newObj의 c의 값을 변경했을 때, obj의 c 값은 변화가 없어야 한다.

그런데 obj의 c 값도 99로 변경되었다.

이러한 현상이 일어나는 이유는 2차원 이상의 객체일 때 내부 객체는 깊은 복사가 되지 않기 때문이다.


방법 2. 스프레드 연산자(...)

const obj = {
  a: 1,
  b: {
    c: 2,
  }
}

const newObj = {...obj};

newObj.b.c = 99;

console.log(obj === newObj); // false
console.log(obj.b.c); // 99
console.log(obj.b.c === newObj.b.c); // true

스프레드 연산자도 2차원 객체는 깊은 복사를 하지 못했다.



2차원 이상의 객체 깊은 복사하기

방법 1. JSON.parse() + JSON.stringify()

JSON.stringify() 메서드를 통해 String 타입으로 변환 후, JSON.parse() 메서드로 다시 객체로 변환해준다.
이 과정에서 두 객체의 참조 관계는 완전히 끊기게 된다.

const obj = {
  a: 1,
  b: {
    c: 2,
  }
}

const newObj = JSON.parse(JSON.stringify(obj))

newObj.b.c = 99;

console.log(obj === newObj); // false
console.log(obj.b.c); // 2
console.log(obj.b.c === newObj.b.c); // false

방법 2. lodash - cloneDeep()

이 방법의 단점은 ladash 라이브러리를 따로 설치해야 한다는 점이다.

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

const newObj = _.cloneDeep(obj);

newObj.b.c = 99;

console.log(obj === newObj); // false
console.log(obj.b.c); // 2
console.log(obj.b.c === newObj.b.c); // false

방법 3. 재귀 함수

const deepCopy = (obj) => {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }

  let copy = {};
  for (let key in obj) {
    copy[key] = deepCopy(obj[key]);
  }
  return copy;
}

const obj = {
  a: 1,
  b: {
    c: 2,
  },
  func: function () {
    return this.a;
  },
};

const newObj = deepCopy(obj);

newObj.b.c = 99;

console.log(obj === newObj); // false
console.log(obj.b.c); // 2
console.log(obj.b.c === newObj.b.c); // false

1개의 댓글

comment-user-thumbnail
2023년 7월 20일

JSON.strigify()를 사용할 경우
값이 undefined인 경우 => property 탈락
값이 NaN인 경우 => null 로 변경

이걸 모르고 쓰면 디버깅이 힘들질 수 있습니다. 방법 중 1가지 일뿐 만능아니란 점

이글을 읽으신 분들께 도움이 되셨으면 좋겠습니다.

답글 달기