실무에서는 여러 단계로 중첩된(nested) JSON 객체를 자주 다루게 됩니다. 다음과 같이 임의의 깊이까지 중첩될 수 있는 JSON 객체가 있다고 가정해 보겠습니다.
const obj = {
"one": 1,
"two": {
"three": 3
},
"four": {
"five": 5,
"six": {
"seven": 7
},
"eight": 8
},
"nine": 9
};목표: 점 표기법으로 된 평면(flat) 객체 만들기
우리가 작성할 자바스크립트 함수는 이처럼 중첩된 JSON 객체를 하나 받아서, 중첩이 전혀 없는 새로운 객체를 반환해야 합니다. 이때 원래의 계층 구조는 점(dot) 표기법을 사용한 키로 변환하여 값을 매핑합니다.
따라서 위 객체를 변환하면 결과는 다음과 같은 형태가 되어야 합니다.
const output = {
'one': 1,
'two.three': 3,
'four.five': 5,
'four.six.seven': 7,
'four.eight': 8,
'nine': 9
};구현 예제
재귀(recursion)를 활용하면 깊이에 상관없이 모든 중첩 구조를 처리할 수 있습니다. 아래 코드의 flattenJSON 함수는 세 가지 매개변수를 받습니다.
- obj: 현재 순회 중인 객체
- res: 최종 결과를 담을 객체
- extraKey: 지금까지 누적된 부모 키 경로
const obj = {
"one": 1,
"two": {
"three": 3
},
"four": {
"five": 5,
"six": {
"seven": 7
},
"eight": 8
},
"nine": 9
};
const flattenJSON = (obj = {}, res = {}, extraKey = '') => {
for (key in obj) {
if (typeof obj[key] !== 'object') {
res[extraKey + key] = obj[key];
} else {
flattenJSON(obj[key], res, `${extraKey}${key}.`);
}
}
return res;
};
console.log(flattenJSON(obj));동작 원리
- 함수는 객체의 각 키를 순회하며 값의 타입을 검사합니다.
- 값이 객체가 아니라면, 누적된 키 경로(
extraKey)와 현재 키를 합쳐 결과 객체에 저장합니다. - 값이 객체라면, 현재 키 뒤에 점(.)을 붙인 경로를 인자로 넘겨 자기 자신을 재귀 호출합니다.
- 모든 순회가 끝나면 완성된 평면 객체를 반환합니다.
참고 사항
자바스크립트에서 typeof null은 'object'를 반환하고 배열 역시 객체로 취급됩니다. 따라서 실제 프로젝트에서는 null이나 배열을 별도로 처리해 주는 것이 더 안전합니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
{
one: 1,
'two.three': 3,
'four.five': 5,
'four.six.seven': 7,
'four.eight': 8,
nine: 9
}이처럼 재귀 함수와 점 표기법을 조합하면, 깊이가 얼마든지 중첩된 JSON 객체도 손쉽게 평탄화할 수 있습니다. API 응답 데이터의 정규화나 로그 분석 등 다양한 상황에서 유용하게 활용할 수 있습니다.