TIL - 14 | 얕은 복사(shallow copy) / 깊은 복사(deep copy)

dk.han·2021년 8월 6일
0
post-thumbnail

일반적인 copy

이 전에 원시 자료형과 참조 자료형에 대해서 배웠다.
그리고 type 별로 일반적인 자료 복사가 이루어 졌을 때 어떠한 변화가 일어나는지 알아보았다.

  • 원시 자료형의 일반적인 copy
    복사본 b의 value가 바뀌어도 원본의 value는 바뀌지 않는다.
let a =1;
let b = a;
b=2

console.log(a); // output = 1
console.log(b); // output = 2
  • 참조 자료형의 일반적인 copy
    value가 복사 되는 것이 아닌, reperence가 복사 되는 것!
    때문에 f를 수정해도 e도 함께 바뀌게 된다.
let e = [10, 20, 30];
let f = e;  // e와 f는 동일한 reference 를 가지게 된다.
f[0] = 50;

console.log(e); // output[50, 20, 30]
console.log(f); // output[50, 20, 30]

얕은 복사 (shallow copy)

얕은 복사는 reference의 복사가 일어나 같은 reference를 가지게 된다.

  • 복사본에서 value를 수정하면 원본의 value도 수정된다.
  • 보통 '=' 연산자로 복사 하게 되면 얕은 복사를 수행한다.
  • 위에서 소개한 참조 자료형의 일반적인 copy가 얕은 복사에 해당된다.
const obj1 = { a: 1, b: 2};
const obj2 = obj1;

console.log( obj1 === obj2 ); // true

obj2.b = 'Hi';

console.log ( obj1.b ); // "Hi"
console.log ( obj2.b ); // "Hi"

깊은 복사 (deep copy)

깊은 복사는 객체의 property나 배열의 element들만 복사해서,
원본과는 다른 새로운 reference를 (새로운 주소) 가지게 되는 복사를 의미한다.

1. (...) spread syntax의 사용.

  • 복사본을 수정했을 때 원본은 변하지 않는다.
  • 다른 reference를 가지게 되는 깊은 복사가 실행되었다.
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = {...obj1 };

console.log( obj1 === obj2 ) // false

obj2.c = "Hello!";

console.log( obj1.c ) // 3
console.log( obj2.c ) // "Hello!"

하지만 이 방법은 1 depth 까지만 깊은 복사가 일어난다.
뒤에서 자세히 알아보자.

2. Object 객체의 assign() 메소드의 사용.

  • value를 똑같이 복사하기 위해서는, 빈 객체에 복사해야한다.
  • obj1 과 obj2는 다른 refence를 가지는 깊은 복사가 실행되었다.
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = Object.assign({}, obj1);

obj2.a = "Hello!";

console.log( obj1 === obj2 ) // false

console.log( obj1.a ) // 1
console.log( obj2.a ) // "Hello!

하지만 이 방법도 1 depth 까지만 깊은 복사가 일어난다.

깊은 복사가 1 depth 까지만 된다는게 무슨 의미?

  • spread syntaxassign() method 둘 다 완벽한 깊은 복사는 되지 않는다.
const obj1 = {team: "DWG", rank: 1, member: ["Khan", "Canyon", "Showmaker"] };
const obj2 = { ...obj1 };
const obj3 = Object.assign({}, obj1);

console.log(obj1 === obj2) // false
console.log(obj2 === obj3) // flase
// 깊은 복사가 잘 실행된 것 같아 보이지만

console.log(obj1.member === obj2.member) // true
console.log(obj2.member === obj3.member) // true
// 각 객체의 member의 reference는 모두 같다

obj2.member[0] = "Beryl"

console.log(obj1.member[0]); // "Beryl"
console.log(obj2.member[0]); // "Beryl"
console.log(obj3.member[0]); // "Beryl"
// member의 reference가 같기 때문에 복사본을 변경하면 원본, 복사본 모두 value 변경.
  • property가 value로 원시 자료형 type을 가지고 있다면 Deep copy (1 depth)
  • property가 value로 참조 자료형 type을 가지고 있다면 shallow copy.
  • 객체로 예시를 들었지만 배열도 똑같다.

그럼 1depth 이상의 deep copy는 어떻게?

  • 1depth 이상 부터는 빈 배열, 빈 객체를 만들고 spread syntax를 사용해서
    value를 넣어주면 할 수 있다.
const obj1 = {team: "DWG", rank: 1, member: ["Khan", "Canyon", "Showmaker"] };
const obj2 = { ...obj1, member: [...obj1.member] };

console.log(obj1 === obj2) // false
console.log(obj1.member === obj2.member) // false

그런데 이게 10depth , 20depth를 가진다면? 이건 너무 빡세다....

그럼 완벽한 Deep copy를 위해서는 ?

  • 재귀함수 사용.
  • Lodash의 cloneDeep 함수 사용.
  • JSON.parse()와 JSON.stringify()함수 사용

이러한 방법들이 있다고는 하는데 아직 배우지 못했으므로...
공부하고나서 자세한 방법은 포스팅 하도록 하겠다.

0개의 댓글