대댓글의 구현을 위해, 각 댓글에는 자신의 조상 댓글의 id를 담는 parent, 대댓글의 id를 담는 children 배열이 있다.
따라서 댓글이 하나의 게시물로부터 트리처럼 뻗어나갈 수 있다. 댓글과 그 대댓글들은 각자 참조하고 있는 id값을 통해서, 대댓글의 대댓글들을 무한히 확인할 수 있는 방식으로 구현되어있다.
이건 Post의 댓글, 대댓글들을 재귀적으로 찾아주는 메소드이다. getRepliesRecursively() 내부의 populate()가 핵심이다. 댓글 1에 달린 대댓글 1-1이 있다면, 그 녀석은 댓글 2보다 상위노출 되어야한다. 따라서 DFS처럼 구현했다. 백엔드에서 주는 _id 값을 통해서 해당 _id에 해당하는 댓글이나 대댓글에 대댓글을 작성할 수 있다.
Object.assign이 가장 빠르며, 유의미하게 lodash의 _.cloneDeep이 가장 느리다.
내가 구현한 커스텀 깊은 복사 메서드는 아래와 같다. 사이사이에 주석을 잘 달아놨으니, 읽어보면 이해가 잘 갈 것이다.
그래도 간단히 설명을 덧붙이자면 재귀적으로 구현했다. 배열이거나 객체면 깊게 들어가서 잘 반환해 주는 식이다.
function cloneDeep(obj) {
if (typeof obj !== 'object' || obj === null) {
// 객체가 아니거나 null인 경우 그대로 반환
return obj;
}
if (Array.isArray(obj)) {
// 배열인 경우 빈 배열 생성 후 요소들을 재귀적으로 복사
return obj.map(item => cloneDeep(item));
} else {
// 객체인 경우 빈 객체 생성 후 속성들을 재귀적으로 복사
const clonedObj = {};
for (const key in obj) {
clonedObj[key] = cloneDeep(obj[key]);
}
return clonedObj;
}
}
lodash가 워낙에 무겁다고 해서 직접 구현도 해보고, 비교도 해봤는데 진짜 차이가 꽤 크긴 하다.
물론 내 구현 방식을 lodash의 deepClone과 비교해 봤을 때 빠진 부분이 분명히 많겠지만(정규식이라던가), 그래도 내가 만든 재귀적인 함수에서도 웬만한 데이터에서의 깊은 복사는 다 할 수 있을 것으로 예상이 된다.
JSON 객체를 이용한 깊은복사 역시 number, string, boolean, object, array, null 에서만 복사가 가능하다. 이를 생각해봤을 때 내가 만든 재귀와 비교해볼만한 메서드는 stringify + parse이며, 직접 구현해서 사용하면 훨씬 편하다는 것을 알 수 있다.
Object.assign은 얕은 복사니까 굳이 신경 쓰진 않겠다.. 그냥 얼마나 빠른지만 궁금했다.
결론
1. 귀찮아도 JSON으로 깊은 복사는 지양하자.
2. 재귀는 아직 내겐 '감'으로 짜는 영역인듯하다. mock 데이터 하나 머리로 떠올리고 함수 하나하나 내부로 들어가서 상상으로 돌려보면 골치 아프다. 최소한 펜이랑 종이는 있어야 할 듯