실무에서는 프로퍼티 값으로 또 다른 객체를 갖는 객체를 자주 다루게 됩니다. 이런 객체는 2~3단계, 혹은 그 이상으로 깊게 중첩되어 있을 수 있습니다. 이 글에서는 재귀(recursion)를 활용해 중첩된 객체 전체에서 원하는 키를 검색하고, 일치하는 모든 값을 배열로 반환하는 방법을 알아보겠습니다.
예시 객체
다음과 같이 사람 이름을 키로 하고, 그 안에 fullName과 details(중첩 객체)를 포함하는 객체가 있다고 가정해 보겠습니다.
const people = {
Ram: {
fullName: 'Ram Kumar',
details: {
age: 31,
isEmployed: true
}
},
Sourav: {
fullName: 'Sourav Singh',
details: {
age: 22,
isEmployed: false
}
},
Jay: {
fullName: 'Jay Grewal',
details: {
age: 26,
isEmployed: true
}
}
}해결해야 할 문제
우리가 작성할 함수는 객체와 문자열을 인자로 받아, 객체 전체를 탐색하면서 해당 문자열과 일치하는 키를 찾고, 일치하는 모든 키의 값을 담은 배열을 반환해야 합니다.
객체가 여러 단계로 중첩되어 있기 때문에, 이 문제에는 반복문만으로 처리하기보다 재귀 호출이 가장 자연스럽고 효율적인 접근 방식입니다. 함수 이름을 recursiveSearch()라고 지정하겠습니다.
recursiveSearch() 전체 코드
const people = {
Ram: {
fullName: 'Ram Kumar',
details: {
age: 31,
isEmployed: true
}
},
Sourav: {
fullName: 'Sourav Singh',
details: {
age: 22,
isEmployed: false
}
},
Jay: {
fullName: 'Jay Grewal',
details: {
age: 26,
isEmployed: true
}
}
}
const recursiveSearch = (obj, searchKey, results = []) => {
const r = results;
Object.keys(obj).forEach(key => {
const value = obj[key];
if (key === searchKey && typeof value !== 'object') {
r.push(value);
} else if (typeof value === 'object') {
recursiveSearch(value, searchKey, r);
}
});
return r;
};
console.log(recursiveSearch(people, 'age'));코드 동작 방식
이 함수의 로직을 단계별로 살펴보면 다음과 같습니다.
1. 먼저 Object.keys()로 메인 객체의 모든 키를 순회합니다.
2. 순회 중 만난 값이 객체라면, 해당 하위 객체를 대상으로 자기 자신을 다시 호출하여(재귀) 원하는 키를 계속 검색합니다.
3. 키가 검색 문자열과 일치하고, 그 값이 객체가 아니라면 즉시 그 값을 results 배열에 저장합니다.
4. 모든 순회가 끝나면 원하는 값들이 담긴 results 배열을 최종적으로 반환합니다.
여기서 한 가지 주목할 점은 results 배열을 세 번째 매개변수의 기본값(default parameter)으로 사용했다는 것입니다. 덕분에 재귀 호출 시 같은 배열을 계속 공유하면서 값을 누적할 수 있어, 별도의 외부 변수 없이 깔끔하게 구현됩니다.
시간 복잡도
이 함수의 시간 복잡도는 O(m × n)입니다. 여기서 n은 메인 객체 내부의 자식 객체 수, m은 가장 깊은 중첩 단계를 의미합니다. 객체의 깊이가 깊어질수록 재귀 호출이 그만큼 더 진행되기 때문입니다.
다른 키로 검색하기
같은 함수를 활용하면 어떤 키든 손쉽게 검색할 수 있습니다. 예를 들어 isEmployed 키로 검색하면 다음과 같은 결과를 얻을 수 있습니다.
console.log(recursiveSearch(people, 'isEmployed')); // [ true, false, true ]
실행 결과
앞서 작성한 코드를 실행하면 콘솔에 다음과 같이 age 키의 값들이 모두 담긴 배열이 출력됩니다.
[ 31, 22, 26 ]