我在Backbone中看到过有关继承的问题: Backbone.js view inheritance。有用,但没有回答我的问题。
我遇到的问题是:
说我有一个课程Panel
(在此示例中为模型);
var Panel = Backbone.Model.extend({
defaults : {
name : 'my-panel'
}
});
然后是AdvancedPanel
;
var AdvancedPanel = Panel.extend({
defaults : {
label : 'Click to edit'
}
});
以下不起作用:
var advancedPanel = new AdvancedPanel();
alert(advancedPanel.get('name')); // Undefined :(
JSFiddle:http://jsfiddle.net/hWmnb/
我想我可以看到我可以通过创建原型的深层副本的一些自定义 extend 函数来实现这一目标,但这似乎是人们可能想要的Backbone继承,有没有一种标准的方法呢?
答案 0 :(得分:3)
设置原型链的Backbone extend
函数,
除其他外,是通用的,用于视图,路由器,模型,
和收藏品。所以它不知道像defaults
这样的细节
或events
并且无法确定扩展类型是否要覆盖
或合并父母中的值。
前进的方法是在实际定义之外明确地做到这一点:
AdvancedPanel.prototype.defaults = _.extend({}, Panel.prototype.defaults, {
label: 'Click me'
});
您对观点也一样:
SomeExtendedView.prototype.events = _.extend({}, SomeBaseView.prototype.events, {
'click button': 'onClick'
});
您实际上也可以在其适当的位置列出默认值, 如果你喜欢。您只需在构造函数定义之外进行合并:
var Base = Backbone.Model.extend({
defaults: {
base: 123
}
});
var Extended = Base.extend({
defaults: {
extended: 456
}
});
Extended.prototype.defaults = _.extend({}, Base.prototype.defaults, Extended.prototype.defaults);
Extended.defaults
包含base
,extended
和console.log(JSON.stringify(new Extended({ test: 'Hey' }).toJSON()));
>> {"base":123,"extended":456,"test":"Hey"}
传递给实例化的任何属性:
{{1}}
答案 1 :(得分:2)
提到这一点,我写了一个简单的advancedExtend
方法来替换该行(来自this inheritance construct):
Panel.extend = Backbone.Model.extend;
使用:
Panel.extend = advancedExtend;
我的advancedExtend
方法如下所示:
function advancedExtend(protoProps, classProps) {
var delegate = this.render ?
Backbone.View : (this.save ?
Backbone.Model : (this.navigate ?
Backbone.Router : Backbone.Collection));
var child = delegate.extend.apply(this, [ protoProps, classProps ]);
_.defaults(child.prototype.defaults, this.prototype.defaults);
_.defaults(child.prototype.events, this.prototype.events);
_.defaults(child.prototype.attributes, this.prototype.attributes);
return child;
};
N.B。我意识到delegate
的定义是没有意义的,因为所有的Backbone原型extend
方法都是相同的,但是对于未来的版本来说这可能更加健壮。
请参阅JSFiddle here。
我很想知道Backbone老兵对这种方法的看法,因为它是非标准的......
答案 2 :(得分:1)
问题是,使用JavaScript时你没有经典继承,所以你需要在这里做一些特别的事情。
当您使用_.extend
列表中距离对象“右侧”最远的对象时,任何名称冲突都会“赢”。
您需要做的是覆盖扩展的定义以处理这些情况,或者将defaults
哈希命名为local_defaults
,并将其合并到initialization
方法
initialize: function(options){
var attrs = _.extend({}, this.defaults, this.local_defaults);
this.set(attrs, {silent: true});
},
这样的事情。您必须将属性哈希设置为默认值集;通常这发生在模型的构造函数中,但模型只知道该点的默认值。
当然,如果你重新定义local_defaults中的默认值,你仍然会覆盖,所以你会考虑覆盖扩展。 (我们已经为这里的一些具体案例做了很多工作,如果你需要的话,很乐意提供帮助。)
答案 3 :(得分:1)
有几种方法可以实现这一点,但我的应用程序中首选的方法是将模型上的“默认值”定义为函数,因此您可以按照这些方式执行某些操作:
var Panel = Backbone.Model.extend({
defaults : {
name : 'my-panel'
}
});
刚刚定义了您的扩展模型:
var AdvancedPanel = Panel.extend({
defaults: function() {
var d = _.result(Panel.prototype, 'defaults'); // doing this as top level might be a function as well
return _.extend({}, d, {
label : 'Click to edit'
});
}
});
然后在控制台中你应该得到名称正确的值
var advancedPanel = new AdvancedPanelModel();
console.log('advancedPanel', advancedPanel.get('name'));
这应该可以解决问题