Custom comparators и сортировка

Backbone.js предоставляет мощные инструменты для работы с коллекциями моделей через объект Backbone.Collection. Одним из ключевых аспектов управления коллекциями является сортировка элементов, и здесь особую роль играют custom comparators — пользовательские функции сравнения, определяющие порядок элементов в коллекции.


Основы comparator

comparator в Backbone.js используется для определения порядка элементов коллекции. Это свойство может быть задано:

  1. Строкой, соответствующей имени атрибута модели:
var Users = Backbone.Collection.extend({
    comparator: 'age'
});

var users = new Users([
    { name: 'Alice', age: 25 },
    { name: 'Bob', age: 30 },
    { name: 'Charlie', age: 20 }
]);

users.sort();
console.log(users.pluck('name')); // ["Charlie", "Alice", "Bob"]

В этом примере коллекция сортируется по возрастанию значения атрибута age.

  1. Функцией, которая принимает одну модель и возвращает значение для сравнения:
var Users = Backbone.Collection.extend({
    comparator: function(model) {
        return -model.get('age'); // сортировка по убыванию
    }
});

users.sort();
console.log(users.pluck('name')); // ["Bob", "Alice", "Charlie"]

Использование функции дает гибкость: можно применять сложные вычисления или инвертировать порядок сортировки.

  1. Функцией двух аргументов, принимающей две модели, возвращающей число:
var Users = Backbone.Collection.extend({
    comparator: function(a, b) {
        if (a.get('age') < b.get('age')) return -1;
        if (a.get('age') > b.get('age')) return 1;
        return 0;
    }
});

users.sort();

Функция с двумя аргументами полностью контролирует логику сортировки и аналогична стандартной функции сравнения в Array.prototype.sort.


Автоматическая сортировка при добавлении

Если коллекция имеет заданный comparator, то при добавлении новых моделей с помощью add() или reset() коллекция автоматически выполняет сортировку:

users.add({ name: 'Dave', age: 27 });
console.log(users.pluck('name')); // ["Charlie", "Alice", "Dave", "Bob"]

Это поведение можно отключить, передав опцию {sort: false}.


Изменение comparator на лету

comparator может быть изменён динамически для коллекции, что позволяет пересортировать элементы по новому критерию:

users.comparator = function(model) {
    return model.get('name'); // сортировка по имени
};
users.sort();
console.log(users.pluck('name')); // ["Alice", "Bob", "Charlie", "Dave"]

При этом важно помнить: изменение comparator не изменяет порядок коллекции автоматически до вызова sort().


Сортировка с учётом нескольких критериев

Иногда требуется сортировать по нескольким атрибутам. Для этого удобно использовать функцию с двумя аргументами:

var Users = Backbone.Collection.extend({
    comparator: function(a, b) {
        var ageCompare = a.get('age') - b.get('age');
        if (ageCompare !== 0) return ageCompare;
        return a.get('name').localeCompare(b.get('name'));
    }
});

В этом примере коллекция сортируется сначала по возрасту, а при равенстве возраста — по имени.


Методы сортировки

  • sort() — принудительно сортирует коллекцию по текущему comparator.
  • sortBy() — возвращает отсортированный массив значений, не изменяя исходную коллекцию. Использует функцию, аналогичную comparator:
var sortedNames = users.sortBy(function(model) {
    return model.get('age');
});
  • pluck() — используется для извлечения атрибутов после сортировки.

Практические рекомендации

  • Для простых сортировок достаточно строки с именем атрибута.
  • Для сложных или динамических условий лучше использовать функцию с одним или двумя аргументами.
  • Сортировка коллекции не влияет на модели, только на порядок их хранения в коллекции.
  • Сортировка с использованием sortBy() подходит для временных выборок, когда не требуется менять исходный порядок коллекции.

Оптимизация производительности

  • Частые вызовы sort() могут быть затратными при больших коллекциях. Рекомендуется группировать изменения моделей и вызывать sort() один раз.
  • При использовании функции comparator с вычислениями стоит кэшировать результаты, если они повторяются для большого числа элементов.

Custom comparators в Backbone.js обеспечивают гибкий и мощный способ управления порядком моделей в коллекции, позволяя реализовать сортировку как по простым атрибутам, так и по сложным критериям с несколькими уровнями сравнения.