문제 상황
다음과 같이 중간중간 빈 인덱스(hole)가 포함된 배열 리터럴이 있다고 가정해 보겠습니다.
const arr = [4, 6, , 45, 3, 345, , 56, 6];
이 배열에서 undefined 또는 빈(empty) 요소만 골라내어 원본 배열 자체에서(in-place) 제거하는 JavaScript 함수를 작성해야 합니다. 여기서 주의할 점은 0, '', false처럼 falsy로 평가되는 모든 값을 지우는 것이 아니라, 오직 undefined와 빈 값만 제거해야 한다는 것입니다.
접근 방법
가장 직관적인 방법은 for 루프로 배열을 순회하면서, undefined인 요소를 만날 때마다 Array.prototype.splice() 메서드로 해당 요소를 제거하는 것입니다. splice()는 원본 배열을 직접 수정하기 때문에 새로운 배열을 만들 필요 없이 제자리 삭제가 가능합니다.
한 가지 유의할 점이 있습니다. 요소를 하나 제거하면 배열의 길이가 줄어들고 뒤쪽 요소들이 앞으로 당겨집니다. 따라서 현재 요소가 undefined가 아닐 때만 인덱스 i를 증가시키고, undefined일 때는 splice()로 제거한 후 인덱스를 그대로 유지해야 합니다. 그렇지 않으면 연속된 빈 값이 존재할 경우 일부 요소를 건너뛰게 되어 제대로 처리되지 않습니다.
예제 코드
위 로직을 구현한 코드는 다음과 같습니다.
const arr = [4, 6, , 45, 3, 345, , 56, 6];
const eliminateUndefined = arr => {
for(let i = 0; i < arr.length; ){
if(typeof arr[i] !== 'undefined'){
i++;
continue;
};
arr.splice(i, 1);
};
};
eliminateUndefined(arr);
console.log(arr);
실행 결과
콘솔에는 다음과 같이 빈 인덱스가 모두 제거된 배열이 출력됩니다.
[
4, 6, 45, 3,
345, 56, 6
]
참고: filter()를 활용한 대안
원본 배열을 유지하고 새 배열을 만들어도 된다면, filter() 메서드를 사용하는 것이 더 간결합니다.
const cleaned = arr.filter(el => el !== undefined);
다만 filter()는 항상 새로운 배열을 반환하므로, 문제의 요구 사항처럼 반드시 제자리(in-place)에서 수정해야 하는 경우에는 앞서 소개한 splice() 방식을 사용해야 합니다.