본문 바로가기
언어/Javascript, Typescript

[js] 2차원 이상 객체의 복사 (얕은 복사 vs 깊은 복사)

by minhyeok.lee 2023. 6. 28.
반응형

1차원 객체일 때는 깊은 복사가 되는 방법들이 2차원 이상부터 내부객체에 대하여 깊은복사가 이루어지지 않을 때 해결하는 방법

 

얕은 복사 (Shallow copy)란?

 - 주소 값을 복사하기 때문에 참조하고 있는 실제 값이 같아 원본과 복사본이 서로 영향을 받는다.


깊은 복사 (Deep copy)란?

 - 실제 값을 독립적인 새로운 메모리 공간에 복사, 참조를 공유하지 않아 원본과 복사본이 서로 영향을 받지 않는다.

 

2023.02.16 - [개발 용어 정리] - [개발용어] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)

 

[개발용어] 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)

얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy) A = 원본 B = 복사하려는 객체 얕은 복사 새로운 B객체를 생성 후 원본 A객체를 메모리 영역을 참조해서 원본에 종속된 객체를 생성하는 것이 얕은 복사

kfdd6630.tistory.com

 


 

2차원 이상의 객체 얕은 복사가 되는 경우

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

 

방법 1. Object.assign()

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

const clone = Object.assign({}, original);

// clone(복사본)의 값을 변경했을 때
clone.b.c = 3;
console.log(original === clone); // false 출력
console.log(original.b.c); // 3 출력
console.log(original.b.c === clone.b.c); // true 출력

 

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

const original = {
  a: 1,
  b: {
    c: 2,
  }
}
const clone = {...obj};
clone.b.c = 3;
console.log(original === clone); // false 출력
console.log(original.b.c); // 3 출력
console.log(original.b.c === newObj.b.c); // true 출력

 

 - 위 두 방법 모두 original과 clone이 다른 것으로 보아 두 객체는 다른 참조 값을 갖는다.

 - 따라서 clone의 c의 값을 변경했을 때, obj의 c 값은 변화가 없어야 하지만 obj의 c 값도 3으로 변경되었다.

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

 

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

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

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

const clone = JSON.parse(JSON.stringify(original))

clone.b.c = 3;

console.log(original === clone); // false 출력
console.log(original.b.c); // 2 출력
console.log(original.b.c === clone.b.c); // false 출력

JSON.stringify() 메서드를 통해 String 타입으로 변환 후, JSON.parse() 메서드로 다시 객체로 변환해준다.

이 과정에서 두 객체의 참조 관계는 완전히 끊기게 되어 깊은 복사가 된다.

2023.04.26 - [언어/Javascript,TypeScript] - [js] JSON관련 메소드(JSON.stringify(), JSON.parse())

 

[js] JSON관련 메소드(JSON.stringify(), JSON.parse())

JSON - 메소드 네트워크를 통해 객체를 어딘가에 보내거나 로깅 목적으로 객체를 출력해야 한다면 객체를 문자열로 전환해야 한다. 전환된 문자열엔 원하는 정보가 있는 객체 프로퍼티 모두가 포

kfdd6630.tistory.com

 

방법 2. 재귀 함수

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 original = {
  a: 1,
  b: {
    c: 2,
  },
  func: function () {
    return this.a;
  },
};

const clone = deepCopy(original);
clone.b.c = 3;

console.log(original === clone); // false 출력
console.log(original.b.c); // 2 출력
console.log(original.b.c === clone.b.c); // false 출력

재귀 함수를 사용하여 2차원 이상의 객체일 때 내부 객체까지 깊은 복사를 하여 반환한다.

 

방법 3. lodash & cloneDeep()

const L = require('lodash');

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

const clone = L.cloneDeep(original);

clone.b.c = 3;

console.log(original === clone); // false 출력
console.log(original.b.c); // 2 출력
console.log(original.b.c === clone.b.c); // false 출력

이 방법은 ladash 라이브러리를 설치해서 사용해야 한다.

 

 

 

방법 4. ramda & clone()

const R = require('ramda');

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


const clone = R.clone(original);

clone.b.c = 3;

console.log(original === clone); // false 출력
console.log(original.b.c); // 2 출력
console.log(original.b.c === clone.b.c); // false 출력

이 방법은 ramda 라이브러리를 설치해서 사용해야 한다.

반응형

댓글