이번 글에서는 falsy(거짓 같은) 값을 포함하는 중첩 배열을 입력으로 받아, 중첩 구조를 모두 제거하고 일차원 배열로 만들어주는 JavaScript 함수를 직접 작성해 보겠습니다.
핵심 조건은 라이브러리나 내장 유틸리티 함수에 의존하지 않고 순수 JavaScript만으로 구현한다는 점입니다.
문제 정의
예를 들어 다음과 같은 중첩 배열이 있다고 가정해 봅시다.
const arr = [[1, 2, 3], [4, 5, [5, false, 6, [5, 8, null]]], [6]];
이 배열에는 false와 null 같은 falsy 값이 포함되어 있으며, 여러 겹의 중첩 구조를 가지고 있습니다.
우리가 원하는 출력 결과는 다음과 같습니다.
const output = [1, 2, 3, 4, 5, false, 6, 5, 8, null, 6];
즉, 중요한 점은 falsy 값이라도 배열에서 제거되지 않고 그대로 유지되어야 한다는 것입니다. 많은 개발자가 filter()나 불린 변환 과정에서 이런 값들을 실수로 걸러내기 쉽지만, 여기서는 값 자체를 보존하면서 구조만 평탄화(flatten)해야 합니다.
구현 아이디어
구현 방식은 간단합니다.
- 배열의 각 요소를 순회하면서 해당 요소가 배열인지 확인합니다.
- 배열이라면 재귀적으로 평탄화한 뒤 결과에 합칩니다.
- 배열이 아니라면 그대로 결과 배열에 추가합니다.
코드 예제
다음은 위 로직을 구현한 전체 코드입니다.
const arr = [[1, 2, 3], [4, 5, [5, false, 6, [5, 8, null]]], [6]];
const flatten = function(){
let res = [];
for(let i = 0; i < this.length; i++){
if(Array.isArray(this[i])){
res.push(...this[i].flatten());
}else{
res.push(this[i]);
};
};
return res;
};
Array.prototype.flatten = flatten;
console.log(arr.flatten());코드 설명
코드의 동작 방식을 단계별로 살펴보겠습니다.
- 재귀 함수 정의:
flatten함수는 빈 배열res를 생성하고,this(호출 대상 배열)를 반복문으로 순회합니다. - 배열 여부 검사:
Array.isArray()로 현재 요소가 배열인지 판단합니다. 배열이라면 해당 요소에 대해flatten()을 재귀 호출하고, 스프레드 연산자(...)를 사용해 반환된 배열의 모든 요소를res에 펼쳐 넣습니다. - 일반 값 처리: 배열이 아니라면 그 값을 그대로
res에 추가합니다. 이 과정에서false,null,0,""같은 falsy 값도 조건 분기와 무관하게 그대로 보존됩니다. - 프로토타입 확장: 마지막으로
Array.prototype.flatten에 함수를 할당하여, 어떤 배열에서든.flatten()메서드처럼 호출할 수 있도록 만듭니다.
참고: 실무 코드에서는Array.prototype을 직접 수정하는 것이 예기치 않은 충돌을 일으킬 수 있으므로 권장되지 않습니다. 학습 목적으로는 유용하지만, 프로덕션 환경에서는 일반 함수나 ES2019의Array.prototype.flat(Infinity)를 사용하는 것이 더 안전합니다.
실행 결과
위 코드를 실행하면 콘솔에 다음과 같은 출력이 나타납니다.
[
1, 2, 3, 4,
5, 5, false, 6,
5, 8, null, 6
]출력 결과를 보면 중첩 구조가 완전히 해소되었고, false와 null 같은 falsy 값도 원래 위치의 순서대로 그대로 남아 있는 것을 확인할 수 있습니다.
마무리
이 예제는 재귀 호출과 스프레드 연산자만으로 복잡한 중첩 배열을 안전하게 평탄화할 수 있음을 보여줍니다. 특히 falsy 값을 포함한 데이터를 다룰 때는 필터링 로직이 의도치 않게 값을 삭제하지 않도록 주의하는 것이 중요합니다. 깊이가 얼마든 상관없이 동작하는 이 패턴은 API 응답 데이터 정리, 트리 구조 변환 등 다양한 상황에서 응용할 수 있습니다.