В Backbone.js вычисляемые свойства позволяют создавать динамические значения на основе данных модели, которые автоматически обновляются при изменении исходных атрибутов. Это особенно полезно для построения реактивного интерфейса без необходимости вручную следить за всеми изменениями. В отличие от обычных атрибутов, вычисляемые свойства не хранятся напрямую в модели, а рассчитываются при обращении к ним.
В Backbone.js нет встроенной поддержки вычисляемых свойств в чистом
виде, но их можно реализовать через геттеры в модели или через
библиотеку расширений. Основная идея заключается в переопределении
метода get модели для возвращения динамического
значения:
var Person = Backbone.Model.extend({
defaults: {
firstName: '',
lastName: ''
},
get: function(attr) {
if (attr === 'fullName') {
return this.get('firstName') + ' ' + this.get('lastName');
}
return Backbone.Model.prototype.get.call(this, attr);
}
});
var person = new Person({ firstName: 'Иван', lastName: 'Петров' });
console.log(person.get('fullName')); // Иван Петров
В этом примере fullName является вычисляемым свойством,
которое автоматически формируется на основе firstName и
lastName.
Чтобы изменения в атрибутах модели автоматически отражались в
интерфейсе, применяется система событий Backbone.js. Модель генерирует
событие change:<attribute> при изменении любого
атрибута. Для вычисляемых свойств это событие можно обработать
вручную:
var PersonView = Backbone.View.extend({
initialize: function() {
this.listenTo(this.model, 'change:firstName change:lastName', this.render);
},
render: function() {
this.$el.text(this.model.get('fullName'));
return this;
}
});
var personView = new PersonView({ model: person, el: '#person' });
person.set('firstName', 'Алексей'); // Автоматически обновит текст
С помощью listenTo представление подписывается на
изменения зависимых атрибутов и обновляет вычисляемое свойство при
необходимости.
При сложных вычислениях каждый вызов геттера может быть ресурсоёмким. Для оптимизации можно использовать кэширование:
var Product = Backbone.Model.extend({
defaults: {
price: 0,
taxRate: 0.2
},
_cachedPriceWithTax: null,
get: function(attr) {
if (attr === 'priceWithTax') {
if (this._cachedPriceWithTax === null) {
this._cachedPriceWithTax = this.get('price') * (1 + this.get('taxRate'));
}
return this._cachedPriceWithTax;
}
return Backbone.Model.prototype.get.call(this, attr);
},
set: function(key, val, options) {
Backbone.Model.prototype.set.call(this, key, val, options);
if (key === 'price' || key === 'taxRate') {
this._cachedPriceWithTax = null; // Сбрасываем кэш
}
return this;
}
});
var product = new Product({ price: 100 });
console.log(product.get('priceWithTax')); // 120
product.set('price', 200);
console.log(product.get('priceWithTax')); // 240
Такой подход позволяет уменьшить количество повторных вычислений, сохраняя актуальность значения.
Backbone.ComputedFieldsСуществуют расширения Backbone.js, например
Backbone.ComputedFields, которые предоставляют
декларативный синтаксис для вычисляемых свойств:
var Item = Backbone.Model.extend({
computed: {
total: {
deps: ['price', 'quantity'],
fn: function() {
return this.get('price') * this.get('quantity');
}
}
}
});
var item = new Item({ price: 50, quantity: 3 });
console.log(item.get('total')); // 150
item.set('quantity', 4);
console.log(item.get('total')); // 200
В данном примере вычисляемое свойство total
автоматически отслеживает зависимости и обновляется при изменении
price или quantity.
Вычисляемые свойства в Backbone.js — мощный инструмент для создания динамических моделей и реактивных интерфейсов, позволяющий структурировать данные и облегчить управление их изменениями.