중첩된(nested) 객체를 키 경로가 점(.)으로 이어진 하나의 평면(flat) 객체로 변환해야 하는 경우가 종종 있습니다. 예를 들어 다음과 같은 입력 객체가 주어졌을 때 −
const input = {
a: 0,
b: {x: {y: 1, z: 2}},
c: 3
};함수는 아래와 같은 출력을 반환해야 합니다.
const output = {
a: 0,
'b.x.y': 1,
'b.x.z': 2,
c: 3
}즉, 중첩 객체 내부의 모든 값을 최상위 레벨로 끌어올리되, 원래 위치를 나타내는 키 경로('부모키.자식키' 형태)를 문자열 키로 사용해야 합니다. 이번 글에서는 재귀(recursion)를 활용해 중첩 객체를 평탄화하는 함수를 직접 작성해 보겠습니다.
예제 코드
const obj = {
a: 1,
b: {x: {y: 1, z: 2}},
c: 3
};
const obj1 = {
a: 0,
b: 0,
c: 0
};
const object = { a: 0, b: { x: { y: 1, z: 2 } }, c: 3 };
const stringifyKeys = (obj, str = '', fresh = {}) => {
const keys = Object.keys(obj);
for(let i = 0; i < keys.length; i++){
if(typeof obj[keys[i]] === "object" && !Array.isArray(obj[keys[i]])
&& obj[keys[i]]){
stringifyKeys(obj[keys[i]], str+`${keys[i]}.`, fresh);
}else{
fresh[str+keys[i]] = obj[keys[i]];
};
}
return fresh;
};
console.log(stringifyKeys(obj));
console.log(stringifyKeys(object));
console.log(stringifyKeys(obj1));코드 동작 원리
stringifyKeys 함수는 세 가지 매개변수를 받습니다.
- obj: 현재 처리 중인 객체
- str: 지금까지 탐색한 키 경로 (기본값은 빈 문자열)
- fresh: 최종 결과를 담을 객체 (기본값은 빈 객체)
함수는 Object.keys()로 객체의 모든 키를 순회하며 각 값을 검사합니다. 값이 객체이면서 배열이 아니고 null이 아닌 경우, 현재 키와 점(.)을 경로에 덧붙인 뒤 자기 자신을 재귀적으로 호출합니다. 반대로 원시값, 배열, null인 경우에는 누적된 키 경로를 문자열 키로 사용해 결과 객체에 바로 저장합니다.
배열과 null을 평탄화 대상에서 제외하는 이유는, 배열 요소나 null 값을 불필요하게 펼치지 않고 하나의 완전한 값으로 취급하기 위함입니다.
실행 결과
콘솔에는 다음과 같은 결과가 출력됩니다.
{ a: 1, 'b.x.y': 1, 'b.x.z': 2, c: 3 }
{ a: 0, 'b.x.y': 1, 'b.x.z': 2, c: 3 }
{ a: 0, b: 0, c: 0 }중첩 객체는 'b.x.y', 'b.x.z'처럼 점으로 연결된 키로 성공적으로 변환되었으며, 이미 평면적인 구조였던 obj1은 그대로 유지되는 것을 확인할 수 있습니다.