얕은복사(spread) & 깊은복사

이재홍·2022년 1월 15일
0
post-custom-banner

객체의 복사

객체(배열포함)는 변수에 저장될 때 메모리의 주소 값이 저장됩니다.
따라서 const로 선언한 객체 자체를 새로운값으로 재할당 하는 것이 아닌 객체의 요소를 바꾸는 것은 가능합니다.

const a = { name: '철수' }
a.name = '영희'
console.log(a) // { name: '영희' }

하지만 복사할 때는 문제가 발생합니다.

const a = { name: '철수' }
const b = a;
console.log(b) // { name: '철수' }
b.name = '영희'
console.log(a) // { name: '영희' }

변수 b에 a를 복사한 뒤 b만 이름을 영희로 바꿔주고 싶지만 a도 같이 바뀝니다.
주소값이 복사되었기 때문에 서로 같은 주소를 참조하여 어느 쪽을 바꾸든 같이 바뀌게 됩니다.

  • 참조자료(Object, Array, Function)가 아닌 원시자료(String, Number, Boolean, undefined, null)값들은 그대로 대입해도 복사가 됩니다.

얕은복사(spread)

이를 해결 하기위해 스프레드 연산자를 활용해 보았습니다.
스프레드 연산자는 객체 혹은 배열의 요소들을 펼치는 기능을 합니다.

const child1 = {
  name: '철수',
  age: 13,
  school: '다람쥐초등학교'
}

const child2 = {
  ...child1,
  name: '영희'
}

console.log(child1) // { name: '철수', age: 13, school: '다람쥐초등학교' }
console.log(child2) // { name: '영희', age: 13, school: '다람쥐초등학교' }

객체의 속성들만 펼쳐 새로운 객체를 선언 했기에 영희가 잘 변경된걸 확인할 수 있습니다.
객체 리터럴{} 내에서 같은 키(name)의 값(child2.name = '영희')은 덮어 씌워집니다.

  • 스프레드 연산자는 배열에도 사용할 수 있고,
    배열에서는 같은 배열을 여러번 spread할 수도 있습니다.
const a = [1, 2, 3]
const b = [0, ...a, 4, ...a]

console.log(b) // [0, 1, 2, 3, 4, 1, 2, 3]

하지만 spread는 1레벨의 깊이에서의 속성만 복사가 되기에 다음과 같이 속성의 값으로 객체가 있다면 복사가 아닌 참조를 하게 됩니다.

const child1 = {
  name: {
    first: '김',
    last: '철수',
  },
  age: 13,
  school: '다람쥐초등학교',
}

const child2 = {
  ...child1
}

child2.name.first = '안'

console.log(child1);
/*
{
  name: { first: '안', last: '철수' },
  age: 13,
  school: '다람쥐초등학교'
}
*/

깊은복사

const child1 = {
  name: '철수',
  age: 8,
  etc: {
    school: '다람쥐초등학교',
    money: 2000,
    hobby: '수영',
  }
}

const child2 = JSON.parse(JSON.stringify(child1));

child2.etc.school = '토끼초등학교';

console.log(child1);

/*
{
  name: '철수',
  age: 8,
  etc: { school: '다람쥐초등학교', money: 2000, hobby: '수영' }
}
*/

JSON.stringify()는 객체를 통째로 문자열로 바꿔주고
바꿔준 문자열 값을 다시 JSON.parse()를 사용해 새객체로 만들어 주기에 깊은복사가 됩니다.
객체뿐만 아니라 배열에도 사용이 가능합니다. (배열 -> 문자 -> 배열)

  • 다만 실무에선 느려서 이 방법은 사용하지 않고
    npm의 lodash를 다운 받아 cloneDeep 메서드를 이용합니다.
import lodash from 'lodash';

const a = { x: { y: 1 } };
const b = lodash.cloneDeep(a);
post-custom-banner

0개의 댓글