[JavaScript, ES6] 중첩된 객체의 깊은 복사 방법

Jason·2022년 9월 1일
2

Jason's TIL

목록 보기
1/1

얕은복사 깊은복사 밈

전개연산자로 쉽게 할... 어라? 🤨

React는 객체(배열 포함) 상태가 변경 될때 이전과 이후를 비교 (Virtual DOM 특성) 하여 수정되는 '부분만' 변경 하려고 하는 습성이 있고, 원본 값의 훼손을 방지하고자 카피된 변수를 따로 만들어 깊은 복사 과정을 거쳐 카피 변수를 리턴하여 객체 상태에 적용하는 것이 일반적입니다.

하지만! 일반적인 데이터의 형태는 자고로 배열 안에 여러개의 객체 덩어리가 있는 방식입니다. 배열 안에 객체로 중첩된 상태는 전개 연산자로 중첩된 곳까지 깊은 복사가 적용이 안되는 것을 알게 되었습니다.

- 중첩 형태가 아닐 경우

const exampleData = ['암온더','넥스트',''];
const copyData = [...example];

copyData[2] = '래블';

console.log(exampleData);
// ['암온더', '넥스트', '']
console.log(copyData);
// ['암온더', '넥스트', '래블']

- 중첩 형태일 경우

const exampleData = [
  {id: 0, name: '둘리', age: 8},
  {id: 1, name: '도우너', age: 8},
  {id: 2, name: '또치', age: 20},
];
const copyData = [...example];

copyData[2].name = '마이콜';

console.log(exampleData[2].name);
// '마이콜'
console.log(copyData[2].name);
// '마이콜'

해결방법

1. JSON 객체 메서드 사용

서버와 웹 클라이언트가 문자열로 이루어진 데이터를 통신을 하기위해 변환 기능을 지원하는 내장 객체 메서드 JSON을 활용하여 중첩된 곳까지 깊은 복사를 할 수 있습니다. 해당되는 예시데이터를 stringify 메서드로 문자열로 만든 다음, parse 메서드로 다시 객체형태로 변환을 하면 됩니다.

const exampleData = [
  {id: 0, name: '둘리', age: 8},
  {id: 1, name: '도우너', age: 8},
  {id: 2, name: '또치', age: 20},
];
const copyData = JSON.parse(JSON.stringify(exampleData));

copyData[2].name = '마이콜';

console.log(exampleData[2].name);
// '또치'
console.log(copyData[2].name);
// '마이콜'

다만 다음과 같은 이유로 해당 방법은 추천드리지 않습니다.

  • 느린속도로 성능에 안좋음
  • 변환 할 수 없는 값은 무시됨 (예를들면 함수 같은)

2. Lodash 라이브러리 사용

일반적인 프로그래밍 작업을 위한, JavaScript 라이브러리 중 하나로써
손쉽게 깊은 복사를 할 수 있습니다.

const exampleData = [
  {id: 0, name: '둘리', age: 8},
  {id: 1, name: '도우너', age: 8},
  {id: 2, name: '또치', age: 20},
];
const copyData = _.cloneDeep(exampleData);

copyData[2].name = '마이콜';

console.log(exampleData[2].name);
// '또치'
console.log(copyData[2].name);
// '마이콜'

3. 재귀 함수 사용

함수 안에 또 다시 함수를 호출하여 참조된 객체를 분리시키는 작업을 하여
깊은 복사를 하는 함수를 사용 할 수 있습니다.

const cloneObject = (obj) => {
  const clone = {};
  for (let key in obj) {
    if (typeof obj[key] == "object" && obj[key] != null) {
      clone[key] = cloneObject(obj[key]);
    } else {
      clone[key] = obj[key];
    }
  }
  return clone;
};

const exampleData = [
  {id: 0, name: '둘리', age: 8},
  {id: 1, name: '도우너', age: 8},
  {id: 2, name: '또치', age: 20},
];
const copyData = cloneObject(exampleData);

copyData[2].name = '마이콜';

console.log(exampleData[2].name);
// '또치'
console.log(copyData[2].name);
// '마이콜'

마치며..

벤치마크로 성능을 비교 했을 경우

  1. 재귀 함수
  2. Lodash 라이브러리
  3. JSON 객체 메서드

순으로 성능이 좋은 것으로 나타나고 있습니다.

사실상 immerJS를 사용하면 따로 깊은복사 과정을 거칠 필요 없이 객체형태인 상태를 손쉽게 반영 할 수 있는걸로 알고있습니다.
그래도 알아둬서 나쁠건 없기 때문에 포스팅 하고 갑니다용 ㅎ :)

참고자료

profile
FE Developer JS(Jason, Jinseong)가 JS(JavaScript)를 합니다.

0개의 댓글