개인적인 프로젝트를 진행하던 도중 lodash 라이브러리의 merge를 알게되었고
기존에는 Shallow와 Deep 을 생각하면 Copy 밖에는 몰랐는데
이번 계기를 통해 shallow merge와 deep merge에 대해 알아보게 되었음.
일단 Shallow Merge란, Shallow Copy, Deep Copy 에서의 Shallow Copy와 비슷한 개념으로
객체의 내부값을 상세히 비교하여 병합하는 것이 아니라
객체를 비교하여 일치하는 key값이 존재할 경우, 그 value값을 바꿔치기 하는 방식 이다.
이를 실행할 수 있는 방법을 두가지가 있는데 지금부터 알아보자.
첫번째 방법으로는 Object 객체의 내장 메소드인 assign을 사용하는 것이다.
const A1 = {
B: 1
};
const A2 = {
C: 2
};
Object.assign({}, A1, A2); // {B: 1, C: 2}
위의 사용예제를 보면 기본적으로 Object.assign은
첫번째 인자로 들어온 값을 기준으로 나머지 인자들을 병합하는 메소드이다.
그렇다면 객체의 depth가 한 단계 증가하면 어떻게 될까?
const A3 = {
B: {
C: 1
}
}
const A4 = {
B: {
D: 2
}
}
Object.assign({}, A3, A4); // {B: { D: 2 }}
Object.assign은 이전에 언급했던 것과 같이, Shallow Merge이기 때문에
Depth를 1단계까지만 비교하고, 그 Depth안에서 동일한 Key값이 존재할 경우
다른 값으로 인지하여 value를 대체해버린다.
두번째 Shallow Merge 방법으로는 ES6의 Spread Operator를 사용하는 것이다.
먼저 Spread Operator를 사용한 예시 코드부터 보고 가자.
const A1 = {
B: 1
};
const A2 = {
C: 2
};
const A12 = { ...A1, ...A2 };
console.log(A12); // {B: 1, C: 2};
const A3 = {
B: {
C: 1
}
}
const A4 = {
B: {
D: 2
}
}
const A34 = { ...A3, ...A4 };
console.log(A34); // {B: { D: 2 }}
Spread Operator 역시 Object.assign 과 동일하게
Depth가 1인 경우에는 생각대로 병합이 되었지만,
Depth가 2이상인 경우부터는 Shallow Merge되어 동일한 Key값에 대한 Value를 대체하는 것을 볼 수 있다.
그렇다면 둘의 차이는 무엇일까?
아래의 코드를 보자.
// Case 1) Object.assign
const A1 = {
B: 1
};
const A2 = {
C: 2
};
Object.assign(A1, A2); // {B: 1, C: 2}
console.log(A1); // {B: 1, C: 2}
// Case 2) Spread Operator
const A3 = {
B: 1
};
const A4 = {
C: 2
};
const A34 = { ...A3, ...A4 };
console.log(A34); // {B: 1, C: 2}
console.log(A3); // { B: 1 }
위의 예제를 보면 Object.assign의 경우 이전에 언급한 것과 같이
첫번째 인자를 기준으로 나머지 인자를 넣어 병합하는 방식이기 때문에
첫번째 인자의 값 자체에 변화가 같이 생기는 상황이 발생한다.
이에 반해, Spread operator 를 사용하는 경우에는
빈 객체에 병합할 객체들을 반복 호출하여 내용을 채워넣는 방식이기 때문에
인자로 들어온 값 자체에 변화는 생기지 않는다는 차이점이 있다.
그렇다면 Depth가 2이상인 경우도 비교하여 Merge하는 방법은 무엇이 있을까 ?
이를 알아보기전에 한가지 생각해볼 것이 있다.
위와 같이 Depth가 2인 경우를 예시로 들었을 때, 생각해보면 Merge의 방법에는 두가지가 있다.
첫번째로는 둘을 병합하여 하나의 객체 안에 병합시키는 방법이다.
두가지 예시의 인자 값으로는 위에서 사용한 A3, A4 변수를 사용하겠다.
B: [
{
C: 'C2',
D: 'D',
E: 'E'
}
]
두번째로는 둘을 병합하여 해당 키값에 각각의 객체에서 가지고 온 값을 따로 가지고 있는 경우이다.
B: [
{
C: 'C1',
D: 'D'
},
{
C: 'C2',
E: 'E'
}
]
자 이제부터 이 두가지 return 값 중 우리가 원하는 병합 값을 얻는 방법에는 어떤 것이 있는지 알아보자.
먼저 소개할 방법은 자바스크립트의 유틸리티 라이브러리인 lodash를 사용하는 방법이다.
lodash 라이브러리에는 Deep Merge를 가능하게 해주는 merge함수가 존재한다.
사용법은 아래와 같다.
import merge from 'lodash/merge'
const A3 = {
B: {
C: 'C1',
E: 'E'
}
}
const A4 = {
B: {
C: 'C2'
D: 'D',
}
}
console.log(merge(A3, A4));
// console
{
B: [
{
C: 'C2',
D: 'D',
E: 'E'
}
]
}
위의 예시에서 보다시피 lodash를 사용할 경우에는 첫번째 방식의 병합이 이루어진다.
두번째 방법으로는 deepmerge 라이브러리를 사용하는 것이다.
import deepmerge from 'deepmerge'
deepmerge(A1, A2)
{
B: [
{
C: 'C1',
D: 'D'
},
{
C: 'C2',
E: 'E'
}
]
}
deepmerge 라이브러리의 deepmerge 함수를 사용할 경우에는
우리가 보았던 두번째 방식의 병합이 이루어지는 것을 볼 수 있다.
프로젝트를 진행하던 도중 deep merge 방식이 필요하여 공부하게 되었는데
기존에 알고있던 Shallow Merge와의 차이를 확실하게 알 수 있었다.
++) 해당 글은
https://blog.ull.im/engineering/2019/04/01/javascript-object-deep-copy.html
를 보고 공부한 내용을 토대로 정리한 글입니다.