Создание экземпляра компаратора

Встроенный объект Intl предоставляет набор инструментов для локализованной обработки текста, чисел и дат. В контексте сортировки строк ключевую роль играет Intl.Collator — специализированный компаратор, учитывающий языковые правила, регистр, диакритику и особенности локали.

Создание экземпляра компаратора — это первый шаг к управляемому сравнению строк, отличающемуся от простого лексикографического сравнения оператором < или методом localeCompare. В отличие от встроенного сравнения Unicode-кодов, Intl.Collator опирается на стандарты UCA (Unicode Collation Algorithm), обеспечивая предсказуемое поведение в разных языковых средах.


Базовое создание экземпляра

Экземпляр компаратора создаётся через конструктор:

const collator = new Intl.Collator();

Без параметров создаётся объект, использующий локаль окружения (runtime default locale). Это означает, что поведение сравнения зависит от системных настроек или конфигурации среды выполнения.

Созданный объект предоставляет метод:

collator.compare('a', 'b');

Метод возвращает:

  • отрицательное число — если первая строка меньше второй
  • положительное число — если первая строка больше второй
  • 0 — если строки эквивалентны с точки зрения правил сравнения

Использование локали при создании

Первый параметр конструктора задаёт язык или список языков:

const collator = new Intl.Collator('ru');

Локаль влияет на порядок сортировки, особенно для символов национальных алфавитов. Например, в русском языке учитываются особенности букв «ё», «е», «й» и других специфических элементов алфавита.

Допускается передача массива локалей:

const collator = new Intl.Collator(['en-US', 'ru']);

В этом случае выбирается первая поддерживаемая локаль из списка, что позволяет реализовать fallback-логику.


Опции конфигурации компаратора

Второй аргумент конструктора определяет поведение сравнения:

const collator = new Intl.Collator('en', {
  sensitivity: 'base',
  ignorePunctuation: true
});

sensitivity

Опция sensitivity управляет уровнем различий, которые учитываются при сравнении:

  • "base" — игнорируются регистр и диакритика
  • "accent" — учитываются диакритические знаки, но игнорируется регистр
  • "case" — учитывается регистр, но игнорируются диакритики
  • "variant" — учитываются все различия

Пример влияния:

const base = new Intl.Collator('en', { sensitivity: 'base' });

base.compare('a', 'A'); // 0
base.compare('a', 'á'); // 0

numeric

Опция numeric включает числовое сравнение внутри строк:

const collator = new Intl.Collator('en', {
  numeric: true
});

При включённом режиме строки с числами сравниваются по их числовому значению:

collator.compare('file2', 'file10'); // отрицательное значение

Без этой опции сравнение происходило бы по символам Unicode, что приводило бы к обратному порядку.


caseFirst

Опция caseFirst определяет приоритет регистра:

  • "upper" — заглавные символы идут первыми
  • "lower" — строчные символы идут первыми
  • "false" — регистр не влияет
const collator = new Intl.Collator('en', {
  caseFirst: 'upper'
});

ignorePunctuation

Позволяет игнорировать знаки препинания:

const collator = new Intl.Collator('en', {
  ignorePunctuation: true
});

Полезно при сортировке заголовков, где символы вроде ,, -, : не должны влиять на порядок.


Повторное использование экземпляра

Экземпляр Intl.Collator является неизменяемым после создания. Это важное свойство:

  • настройки фиксируются при инициализации
  • метод compare не изменяет состояние объекта
  • один экземпляр можно безопасно использовать многократно

Это позволяет эффективно применять компаратор при сортировке массивов:

const collator = new Intl.Collator('ru');

const sorted = ['яблоко', 'ёж', 'арбуз'].sort(collator.compare);

Привязка метода compare

Метод compare можно передавать напрямую, однако в некоторых средах требуется явная привязка:

const collator = new Intl.Collator('en');

const compare = collator.compare.bind(collator);

Без привязки возможна потеря контекста, что приводит к ошибкам в некоторых реализациях.


Локализация и fallback-механизм

При создании компаратора движок выполняет выбор локали:

  1. Проверка точного совпадения
  2. Поиск совместимой локали (language fallback)
  3. Использование системной локали

Пример:

const collator = new Intl.Collator('fr-CA');

Если fr-CA недоступна, может быть использована fr, затем дефолтная локаль среды.


Использование в сложных структурах данных

Компаратор применяется не только к строкам, но и к объектам через проекцию:

const collator = new Intl.Collator('en');

const users = [
  { name: 'Zoe' },
  { name: 'Adam' }
];

users.sort((a, b) => collator.compare(a.name, b.name));

Такой подход сохраняет локализованную логику сортировки при работе со сложными данными.


Производительность создания экземпляра

Создание Intl.Collator является относительно дорогой операцией по сравнению с вызовом compare. Поэтому применяется стратегия переиспользования:

  • экземпляр создаётся один раз
  • хранится в области модуля или сервиса
  • используется многократно
const collator = new Intl.Collator('en', { numeric: true });

export function sortNames(list) {
  return list.sort(collator.compare);
}

Влияние движка на реализацию

Хотя спецификация Intl определяет поведение, конкретная реализация зависит от движка (V8, SpiderMonkey, JavaScriptCore). Это может влиять на:

  • скорость сравнения
  • поддержку отдельных локалей
  • поведение при редких символах Unicode

Однако API и результат compare остаются стандартизированными.


Связь с localeCompare

Intl.Collator является более производительным и гибким аналогом:

'a'.localeCompare('b', 'en', { numeric: true });

эквивалентно:

const collator = new Intl.Collator('en', { numeric: true });
collator.compare('a', 'b');

Разница проявляется при массовой сортировке: Intl.Collator предпочтительнее за счёт переиспользуемого состояния и оптимизаций.


Использование в многоязычных системах

В приложениях с поддержкой нескольких языков компаратор создаётся динамически:

function createUserCollator(locale) {
  return new Intl.Collator(locale, {
    sensitivity: 'base',
    numeric: true
  });
}

Такой подход позволяет унифицировать сортировку при смене языка интерфейса без изменения бизнес-логики.