초반 프로젝트를 진행했을때, 객체를 초기값으로 다시 되돌리는 작업을 했었는데 해당 작업을 Lodash의 cloneDeep()으로 해결했습니다 하지만 해당 코드 하나때문에 라이브러리에 의존하기 싫었고 또한 어떠한 부분이 문제였는지 제대로 생각해보고싶어서 작성했습니다.
const initialBrideGroom: BrideGroomInformation[] = [
{
role: '신랑',
name: '',
relation: '아들',
family: {
father: { name: '', isDeceased: false },
mother: { name: '', isDeceased: false },
},
},
{
role: '신부',
name: '',
relation: '딸',
family: {
father: { name: '', isDeceased: false },
mother: { name: '', isDeceased: false },
},
},
];
여기서 family안에 들어있는 객체들이 zustand를 사용하는중에 제대로 초기화가 되지않는 문제가 생겼습니다.
기존에 작성한 reset 함수
reset: () => {
set({ brideGroom: initialBrideGroom });
}
다른 스토어에있는 상태값들은 제대로 초기화되고 해당 상태의 밖에있는 속성값들은 제대로 초기화가 되기때문에 clone의 문제라고 생각되었다.
얕은 복사 깊은 복사 문제 같은데 어디서 부터 잘봇 된거지 ?
우선 이걸 사용중인 zustand는 얕은 복사를 사용하고 있다 이게 문제인가 ?
reset 함수를 실행 시키때 해당 안에 있는 원시값들은 변경이 되수있겠지만 그 안에있는 객체는 다른 하나의 참조값들이라서 여전히 메모리에 남아있는 참조값을 가지고 오기때문에 독립적인 값들로 초기화를 시켜줘야한다
따라서 깊은 복사 필요하다고 생각...
JSON.stringify(obj) → 객체를 JSON 문자열로 바꿈
JSON.parse(...) → 그 문자열을 다시 객체로 바꿈
즉 원시값에 참조값을 바꿔주기떄문에 메모리에 남아있는 참조값을 사용하지않음
하지만 문제열로 바꾸기 때문에
undefined, function, Symbol → 무시됨
Date → 문자열로 변환되어 원래 타입 정보 사라짐
Map, Set, RegExp, Error, BigInt → 무시 or 오류
순환 참조 에러 ...
reset: () => {
set({ brideGroom: JSON.parse(JSON.stringify(initialBrideGroom)) });
}
네이티브 API 브라우저에서 처리 원래 자료형, 참조 구조, 순환 참조까지 완전히 유지하며 복사
structured clone algorithm 사용 재귀적으로 순회하면서 복제하고, 각각의 타입과 구조를 유지해서 새로운 객체를 생성
reset: () => {
set({ brideGroom: structuredClone(initialBrideGroom) });
}
reset: ()=>{
set({ brideGroom: cloneDeep(initialBrideGroom) });
}
reset: () => {
set(() => ({
brideGroom: [
{
role: '신랑',
name: '',
relation: '아들',
family: {
father: { name: '', isDeceased: false },
mother: { name: '', isDeceased: false },
},
},
{
role: '신부',
name: '',
relation: '딸',
family: {
father: { name: '', isDeceased: false },
mother: { name: '', isDeceased: false },
},
},
],
})
해당 방법들을 공부하다보니 Pollyfill이라는 개념을 알게되었다
브라우저나 JS 런타임이 지원하지 않는 기능을, 직접 구현해서 대신 동작하게 만들어주는 코드
즉 오래된 브라우저에서 지원하지 않는 기능들을 직접 구현해서 채워주는 스크립트 (fetch, promise structuredClone 등)
//Array.include 메서드가 존재하지않으면 직접 구현
if (!Array.prototype.includes) {
Array.prototype.includes = function (element) {
return this.indexOf(element) !== -1;
};
}
Pollyfill :기능이 없을 때만 조건부로 정의해서 기존 브라우저 호환성을 확보
Transpile :코드를 다른 버전/형태의 코드로 변환 TypeScript → JavaScript 또는 ES6+ → ES5
Shim : Polyfill과 비슷하지만, 기존 기능을 덮어쓰는 경우도 포함