Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

속성이 없거나 null인 JavaScript 객체 배열, sort() 비교 함수로 정렬하는 방법

실무에서 서버로부터 데이터를 받아오다 보면, 배열 안의 객체마다 특정 속성의 존재 여부가 다른 경우를 자주 만나게 됩니다. 예를 들어 어떤 객체에는 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() 메서드는 비교 함수가 반환하는 값에 따라 요소의 순서를 결정합니다. 음수를 반환하면 ab보다 앞에, 양수를 반환하면 ba보다 앞에 위치하며, 0을 반환하면 순서가 그대로 유지됩니다.

위 비교 함수는 다음과 같은 우선순위로 조건을 검사합니다.

  1. 속성 자체가 없는 경우(undefined): 한쪽에만 date 속성이 존재하면 속성이 없는 쪽을 앞으로 보냅니다.
  2. 양쪽 모두 속성이 없는 경우: localeCompare()name 값을 사전순으로 비교합니다.
  3. 속성은 있지만 값이 null인 경우: null인 쪽을 앞으로 보냅니다.
  4. 양쪽 모두 null인 경우: 순서를 변경하지 않습니다.
  5. 양쪽 모두 날짜 값이 있는 경우: 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');