处理 Backbone.js 中的非持久属性已经有一段时间了,特别是自从我开始使用 ember/ember-data 之后,它通过计算属性、ember-data 属性或控制器来处理各种情况。
许多解决方案建议定制该toJSON
方法。但是,一些流行的 Backbone 插件(尤其是那些处理嵌套模型的插件)实现了自己的toJSON
方法,并调用以Backbone.Model.prototype.toJSON
获取模型属性的对象表示。因此,通过覆盖toJSON
模型定义中的方法,您将失去这些插件的一些(可能至关重要的)功能。
我想出的最好的方法是excludeFromJSON
在模型定义中包含一个键数组,并覆盖自身的toJSON
方法Backbone.Model.prototype
:
Backbone.Model.prototype.toJSON = function() {
var json = _.clone(this.attributes),
excludeFromJSON = this.excludeFromJSON;
if(excludeFromJSON) {
_.each(excludeFromJSON, function(key) {
delete json[key];
});
}
return json;
};
MyModel = Backbone.Model.extend({
excludeFromJSON: [
'inches'
]
});
这样,您只需定义非持久键(如果您忘记这样做,您很快就会在服务器抛出错误时得到提醒!)。如果不存在任何属性,toJSON
则将正常运行。excludeFromJSON
在您的情况下,inches
是一个计算属性,派生自mm
,因此将其作为模型上的方法实现是有意义的(确保在更改 mm 时英寸的值是正确的):
MyModel = Backbone.Model.extend({
inches: function() {
return this.get('mm') / 25;
}
});
但是,这具有与其他所有属性不同的访问方式的缺点。理想情况下,您会希望使其与访问其他属性保持一致。这可以通过扩展默认get
方法来实现:
var getMixin = {
get: function(attr) {
if(typeof this[attr] == 'function') {
return this[attr]();
}
return Backbone.Model.prototype.get.call(this, attr);
}
};
MyModel = Backbone.Model.extend({
inches: function() {
return this.get('mm') / 25;
}
});
_.extend(MyModel.prototype, getMixin);
这会让你做:
new MyModel().get('inches');
这种方法不会触及底层attributes
哈希,这意味着它inches
不会出现在toJSON
表示中,除非你稍后set
的值inches
,在这种情况下你需要像excludeFromJSON
数组这样的东西。
如果您需要set
该inches
值,您可能还想监听变化并调整 的值mm
:
MyModel = Backbone.Model.extend({
initialize: function() {
this.on('change:inches', this.changeInches, this);
},
inches: function() {
return this.get('mm') / 25;
},
changeInches: function() {
this.set('mm', this.attributes.inches * 25);
}
});
_.extend(MyModel.prototype, getMixin);
请参阅JSBin 上的完整示例。
还值得注意的是,该方法的(官方?)目的toJSON
最近被重新定义为准备与服务器同步的模型。出于这个原因,调用toJSON
应该始终只返回“持久”(或“可保存”)属性。