실무에서 서버로부터 데이터를 받아오다 보면, 배열 안의 객체마다 특정 속성의 존재 여부가 다른 경우를 자주 만나게 됩니다. 예를 들어 어떤 객체에는 date 필드가 문자열 형태로 담겨 있지만, 다른 객체에는 이 필드가 null이거나 아예 존재하지 않을 수 있습니다.
이렇게 불균형한 데이터를 단순한 정렬 로직으로 처리하면 오류가 발생하거나 의도와 다른 순서로 정렬됩니다. 이 글에서는 Array.prototype.sort()의 비교 함수(comparator)를 활용해 이런 상황을 깔끔하게 해결하는 방법을 살펴보겠습니다.
요구 사항 정리
- 날짜(
date)가 없는 객체는 목록 맨 위에 배치한다. - 날짜가 없는 객체들끼리는 이름(
name) 기준으로 알파벳순(가나다순) 정렬한다. - 날짜가 있는 객체들은 그 아래에 배치하고, 날짜 오름차순으로 정렬한다.
정렬 코드 예제
const sorter = (a, b) => {
// 한쪽에만 date 속성이 존재하는 경우
if (typeof a.date == 'undefined' && typeof b.date != 'undefined') {
return -1;
} else if (typeof a.date != 'undefined' && typeof b.date == 'undefined') {
return 1;
}
// 양쪽 모두 date 속성이 없는 경우 → 이름순 정렬
else if (typeof a.date == 'undefined' && typeof b.date == 'undefined') {
return a.name.localeCompare(b.name);
}
// date 속성은 있지만 값이 null인 경우
else if (a.date == null && b.date != null) {
return -1;
} else if (a.date != null && b.date == null) {
return 1;
} else if (a.date == null && b.date == null) {
return 0;
}
// 양쪽 모두 날짜 값이 있는 경우 → 날짜 오름차순 정렬
else {
const d1 = Date.parse(a.date);
const d2 = Date.parse(b.date);
return d1 - d2;
}
};코드 동작 원리
sort() 메서드는 비교 함수가 반환하는 값에 따라 요소의 순서를 결정합니다. 음수를 반환하면 a가 b보다 앞에, 양수를 반환하면 b가 a보다 앞에 위치하며, 0을 반환하면 순서가 그대로 유지됩니다.
위 비교 함수는 다음과 같은 우선순위로 조건을 검사합니다.
- 속성 자체가 없는 경우(undefined): 한쪽에만
date속성이 존재하면 속성이 없는 쪽을 앞으로 보냅니다. - 양쪽 모두 속성이 없는 경우:
localeCompare()로name값을 사전순으로 비교합니다. - 속성은 있지만 값이 null인 경우:
null인 쪽을 앞으로 보냅니다. - 양쪽 모두 null인 경우: 순서를 변경하지 않습니다.
- 양쪽 모두 날짜 값이 있는 경우:
Date.parse()로 문자열을 밀리초 단위 타임스탬프로 변환한 뒤 차이를 계산해 오름차순으로 정렬합니다.
실제 사용 예시
const items = [
{ name: 'Banana', date: '2024-05-01' },
{ name: 'Apple', date: null },
{ name: 'Cherry', date: '2023-12-15' },
{ name: 'Mango' }
];
items.sort(sorter);
console.log(items);실행 결과는 다음과 같습니다.
[
{ name: 'Mango' }, // date 속성 없음 → 최상단
{ name: 'Apple', date: null }, // date가 null → 그다음
{ name: 'Cherry', date: '2023-12-15' }, // 날짜 오름차순
{ name: 'Banana', date: '2024-05-01' }
]알아두면 좋은 점
Date.parse()는 ISO 8601 형식(예: '2024-05-01')의 문자열은 안정적으로 처리하지만, 지역화된 날짜 문자열(예: '05/01/2024')은 실행 환경에 따라 파싱 결과가 달라질 수 있습니다. 따라서 서버에서는 ISO 형식의 날짜 문자열을 전달하는 것이 안전합니다.
또한 한국어 환경에서 가나다순 정렬이 필요하다면 localeCompare()에 로케일을 지정할 수도 있습니다.
return a.name.localeCompare(b.name, 'ko');