Deepcopy Shallowcopy 차이 알아보기

시작하기

객체를 두번이상 사용할때 원하지 않았는데 원본의 객체가 수정되는 경우가 있습니다.
자바스크립트 객체를 안전하게 복사하는 방법을 알아보겠습니다.

기본데이터 저장

1
2
3
4
5
let a = "Javascript";
let b = a; // b에 a를 할당
b = "Typescript";
console.log(b); // "Typescript"
console.log(a); // "Javascript"

b에 a를 할당하면 복사본이 생성됩니다. 이 새로운 값에 값을 변경하면 b는 변경되지만 a는 변경되지 않습니다.

복합데이터 저장

가장 문제가 되는 복합데이터입니다. Object, Array가 이에 해당됩니다. 변수를 할당하면 해당 값에 대한 참조 포인터가 생성됩니다.

1
2
3
4
5
6
7
8
9
const a = {
name: "flamingo",
age: 27,
email: "email@gmail.com",
};
let b = a;
b.name = "tiger";
console.log(b.name); // tiger
console.log(a.name); // flamingo

b의 이름만 바꾸었을뿐인데 a의 이름도 같이 바뀌었습니다. 이런 변수가 변경된 값이 아닌 원래 값을 가지고 있기를 기대하고 있어서 문제가 발생합니다. 객체와 배열을 올바르게 복사하는 방법을 알아보겠습니다.

Shallowcopy

Object.assign (ES5)

ES5에서는 Object.assign()을 통해서 복사할 수 있습니다.

1
2
3
4
5
6
7
8
const a = {
name: "flamingo",
age: 27,
};
let b = Object.assign({}, a);
b.name = "tiger";
console.log(b); // tiger
console.log(a); // flamingo

Spread (ES6)

ES6에서는 spread로 복사를 할 수 있습니다.

1
2
3
4
5
6
7
8
const a = {
name: "flamingo",
age: 27,
};
let b = { ...a };
b.name = "tiger";
console.log(b); // tiger
console.log(a); // flamingo

이렇게만 하면 간단하겠지만 문제가 있습니다.
객체 내부에 중첩된 객체가 있을경우 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const a = {
a1: {
name: "a1",
a2: {
name: "a2"
}
}
};
let b = { ...a };
b.a1.name = "b1";
b.a1.a2.name = "b2";
console.log(b);
/*
{
a1: {
name: "b1",
a2: {
name: "b2"
}
}
}
*/
console.log(a);
/*
{
a1: {
name: "b1",
a2: {
name: "b2"
}
}
}
*/

b에서만 바꾸고 싶지만 a에서도 같이 바뀌는것을 확인할 수 있습니다.
해결하기 위한방법으로 수동으로 복사를 하거나 deepcopy를 이용하면 됩니다.

수동복사

위에서 사용한 예시를 이용해서 수동으로 복사해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const a = {
a1: {
name: "a1",
a2: {
name: "a2"
}
}
};
let b = { ...a, a1: { ...a.a1, a2: { ...a.a1.a2 }} };
b.a1.name = "b1";
b.a1.a2.name = "b2";
console.log(b);
/*
{
a1: {
name: "b1",
a2: {
name: "b2"
}
}
}
*/
console.log(a);
/*
{
a1: {
name: "a1",
a2: {
name: "a2"
}
}
}
*/

각자 제대로 복사된 것을 확인할 수 있습니다.

Deepcopy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const a = {
a1: {
name: "a1",
a2: {
name: "a2"
}
}
};
let b = JSON.parse(JSON.stringify(a));
b.a1.name = "b1";
b.a1.a2.name = "b2";
console.log(b);
/*
{
a1: {
name: "b1",
a2: {
name: "b2"
}
}
}
*/
console.log(a);
/*
{
a1: {
name: "a1",
a2: {
name: "a2"
}
}
}
*/

참조를 끊어주는 방법으로 간단하게 복사하였습니다. 하지만 이 방법에도 문제가 있습니다.
객체 내부에 함수가 있다면 그 함수 값은 복사하지 않는다는 것입니다.

손쉬운 copy방법

lodash라이브러리를 이용하면 손쉽게 deepcopy를 할 수 있습니다.

1
npm install lodash
1
2
3
4
const objects = [{ 'a': 1 }, { 'b': 2 }];

const deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);

이것으로 여러가지의 복사방법을 알아보았습니다.

Share