Какой лучший способ переопределить Model.get(attr) в Backbone.js?
Я использую Backbone.js в первый раз, и мне это нравится. В настоящее время я не могу разобраться в динамических атрибутах моделей. Например, скажем, у меня есть модель Person, и я хочу получить полное имя:
var Person = Backbone.Model.extend({
getFullName: function () {
return this.get('firstName') + ' ' + this.get('surname');
}
});
Тогда я мог бы сделать person.getFullName()
. Но я хотел бы сохранить его в соответствии с другими геттерами, более похожими на person.get('fullName')
. Я не вижу, как это сделать без беспорядочно переопределения Person # get. Или это мой единственный вариант?
Это то, что у меня есть до сих пор для переопределяющего варианта:
var Person = Backbone.Model.extend({
get: function (attr) {
switch (attr) {
case 'fullName':
return this.get('firstName') + ' ' + this.get('surname');
break;
case 'somethingElse':
return this.doSomethingClever();
break;
default:
return Backbone.Model.prototype.get.call(this, attr);
}
}
});
Я полагаю, это не страшно, но кажется, что должен быть лучший способ.
Ответы
Ответ 1
Было бы проще?
var Person = Backbone.Model.extend({
get: function (attr) {
if (typeof this[attr] == 'function')
{
return this[attr]();
}
return Backbone.Model.prototype.get.call(this, attr);
}
});
Таким образом, вы также можете переопределить существующие атрибуты с помощью функций. Как вы думаете?
Ответ 2
Я бы подумал об атрибутах в качестве сырья, используемого моделью, чтобы дать ответы на звонящие, задающие вопросы. Мне на самом деле не нравится, когда звонящие слишком много знают о структуре внутренних атрибутов. Его деталь реализации. Что делать, если эта структура изменяется?
Итак, я бы ответил: не делайте этого.
Создайте метод, как вы это сделали, и скройте детали реализации. Его гораздо более чистый код и сохраняет изменения в реализации.
Ответ 3
Фактические свойства, используемые Model.get, сохраняются в свойстве атрибута. Вы можете сделать что-то вроде этого:
// function to cross-browser add a property to an object
function addProperty(object, label, getter, setter) {
if (object.defineProperty){
object.defineProperty(object, label, {getter: getter, setter: setter})
}
else {
object.__defineGetter__(label, getter)
object.__defineSetter__(label, setter)
}
}
// inside the initializer of your model, add a property to the attribute object
var Person = Backbone.Model.extend({
initialize: function(attr, options) {
var t = this;
...
addProperty(this.attributes, 'fullName',
function() {return t.get('firstName') + ' ' + t.get('surname'),
function(val) {...}
)
}
})
Это позволит вам выполнить person.get('fullName') по вашему желанию.
Изменить: Чтобы быть ясным, я согласен с Биллом ниже. На самом деле не стоит мириться с внутренней реализацией backbone.js. Тем более, что это неполно... как насчет escape() вместо get()? И сеттер более сложный, так как он делает валидацию, меняет уведомление и т.д. Теперь мне жаль, что я разместил это:)