我的解决方案是Backbone.Model.prototype.set
用预处理器代理替换:
/**
* Intercept calls to Backbone.Model.set and preprocess attribute values.
*
* If the model has a <code>preprocess</code> property, that property will be
* used for mapping attribute names to preprocessor functions. This is useful
* for automatically converting strings to numbers, for instance.
*
* @param Backbone
* the global Backbone object.
*/
(function(Backbone) {
var originalSet = Backbone.Model.prototype.set;
_.extend(Backbone.Model.prototype, {
set: function(key, val, options) {
if(!this.preprocess) {
return originalSet.apply(this, arguments);
}
// If-else copied from Backbone source
if (typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
for(attr in this.preprocess) {
if(_.has(attrs, attr)) {
attrs[attr] = this.preprocess[attr](attrs[attr]);
}
}
return originalSet.call(this, attrs, options);
},
});
})(Backbone);
在此之后,具有preprocess
属性的模型将使用它来将属性名称映射到预处理器函数。例如,preprocess: { age: parseInt }
意味着无论何时设置属性,都会在实际设置之前age
传递该值。parseInt
没有对应preprocess
条目的属性不会受到影响。
示例用法:
var Thing = Backbone.Model.extend({
preprocess: {
mass: parseInt,
created: function(s) { return new Date(s); },
},
});
var t = new Thing({
label: '42',
mass: '42',
created: '1971-02-03T12:13:14+02:00',
});
console.log(t.get('label')+3); // 423
console.log(t.get('mass')+3); // 45
console.log(t.get('created').toLocaleString('ja-JP', { weekday: 'short' })); // 水
优点
- 该功能适用于所有型号,无需重复代码
- 无需
{ validate: true }
每次调用都发送到set
- 无需在 中重复预处理
validate
,因为这发生在validate
调用之前(这也可能是一个骗局,见下文)
缺点
- 骨干代码的一些重复
- 可能会破坏验证,因为预处理发生在
validate
调用之前。JavaScript 解析方法通常会返回无效值而不是抛出异常(即parseInt('foo')
返回NaN
),因此您应该能够检测到它。