Backbone.js获取并设置嵌套的对象属性

我有一个关于Backbone.js的getset函数的简单问题。

1)使用下面的代码,如何直接获取或设置obj1.myAttribute1?

另一个问题:

2)在模型中,除了默认对象之外,我可以在哪里声明模型的其他属性,以便通过Backbone的get和set方法来访问它们?

var MyModel = Backbone.Model.extend({ defaults: { obj1 : { "myAttribute1" : false, "myAttribute2" : true, } } }) var MyView = Backbone.View.extend({ myFunc: function(){ console.log(this.model.get("obj1")); //returns the obj1 object //but how do I get obj1.myAttribute1 directly so that it returns false? } }); 

我知道我可以这样做:

 this.model.get("obj1").myAttribute1; 

但这是一个好的做法吗?

虽然this.model.get("obj1").myAttribute1问题,但有点问题,因为那样你可能会试图做同样types的事情,

 this.model.get("obj1").myAttribute1 = true; 

但是,如果你这样做,你不会得到myAttribute1的Backbone模型的好处,比如更改事件或validation。

更好的解决scheme是永远不要在你的模型中嵌套POJSO(“普通的旧JavaScript对象”),而是嵌套自定义模型类。 所以它看起来像这样:

 var Obj = Backbone.Model.extend({ defaults: { myAttribute1: false, myAttribute2: true } }); var MyModel = Backbone.Model.extend({ initialize: function () { this.set("obj1", new Obj()); } }); 

那么访问代码将是

 var x = this.model.get("obj1").get("myAttribute1"); 

但更重要的是设置代码将是

 this.model.get("obj1").set({ myAttribute1: true }); 

这将引发适当的变化事件等。 工作示例: http : //jsfiddle.net/g3U7j/

我为此创build了骨干深度模型 – 只需扩展Backbone.DeepModel而不是Backbone.Model,然后就可以使用path获取/设置嵌套的模型属性。 它也保持更改事件。

 model.bind('change:user.name.first', function(){...}); model.set({'user.name.first': 'Eric'}); model.get('user.name.first'); //Eric 

Domenic的解决scheme将工作,但每个新的MyModel将指向相同的Obj实例。 为了避免这种情况,MyModel应该看起来像这样:

 var MyModel = Backbone.Model.extend({ initialize: function() { myDefaults = { obj1: new Obj() } this.set(myDefaults); } }); 

有关完整的解释,请参阅c3rin的答案@ https://stackoverflow.com/a/6364480/1072653

我使用这种方法。

如果你有这样一个Backbone模型:

 var nestedAttrModel = new Backbone.Model({ a: {b: 1, c: 2} }); 

您可以使用以下设置属性“ab”:

 var _a = _.omit(nestedAttrModel.get('a')); // from underscore.js _a.b = 3; nestedAttrModel.set('a', _a); 

现在你的模型将具有如下属性:

 {a: {b: 3, c: 2}} 

随着“改变”事件被解雇。

@pagewil和@Benno与@ Domenic的解决scheme有同样的问题。 我的答案是,而不是写一个简单的Backbone.Model的子类来解决这个问题。

 // Special model implementation that allows you to easily nest Backbone models as properties. Backbone.NestedModel = Backbone.Model.extend({ // Define Backbone models that are present in properties // Expected Format: // [{key: 'courses', model: Course}] models: [], set: function(key, value, options) { var attrs, attr, val; if (_.isObject(key) || key == null) { attrs = key; options = value; } else { attrs = {}; attrs[key] = value; } _.each(this.models, function(item){ if (_.isObject(attrs[item.key])) { attrs[item.key] = new item.model(attrs[item.key]); } },this); return Backbone.Model.prototype.set.call(this, attrs, options); } }); var Obj = Backbone.Model.extend({ defaults: { myAttribute1: false, myAttribute2: true } }); var MyModel = Backbone.NestedModel.extend({ defaults: { obj1: new Obj() }, models: [{key: 'obj1', model: Obj}] }); 

什么NestedModel为你做的是允许这些工作(当myModel通过JSON数据设置时会发生什么):

 var myModel = new MyModel(); myModel.set({ obj1: { myAttribute1: 'abc', myAttribute2: 'xyz' } }); myModel.set('obj1', { myAttribute1: 123, myAttribute2: 456 }); 

在初始化时自动生成模型列表会很容易,但是这个解决scheme对我来说已经足够了。

Domenic提出的解决scheme有一些缺点。 假设你想听“改变”事件。 在这种情况下,“初始化”方法将不会被触发,您的属性的自定义值将被服务器的json对象replace。 在我的项目中,我遇到了这个问题。 我的解决scheme覆盖模型的“设置”方法:

 set: function(key, val, options) { if (typeof key === 'object') { var attrs = key; attrs.content = new module.BaseItem(attrs.content || {}); attrs.children = new module.MenuItems(attrs.children || []); } return Backbone.Model.prototype.set.call(this, key, val, options); }, 

有一个解决scheme没有人想到哪个是很多使用。 你的确不能直接设置嵌套的属性,除非你使用了你可能不需要的第三方库。 然而,你可以做的是做一个原始字典的克隆,在那里设置嵌套属性,并设置整个字典。 小菜一碟。

 //How model.obj1 looks like obj1: { myAttribute1: false, myAttribute2: true, anotherNestedDict: { myAttribute3: false } } //Make a clone of it var cloneOfObject1 = JSON.parse(JSON.stringify(this.model.get('obj1'))); //Let's day we want to change myAttribute1 to false and myAttribute3 to true cloneOfObject1.myAttribute2 = false; cloneOfObject1.anotherNestedDict.myAttribute3 = true; //And now we set the whole dictionary this.model.set('obj1', cloneOfObject1); //Job done, happy birthday 

虽然在某些情况下,使用Backbone模型而不是嵌套的Object属性是有道理的,但在更简单的情况下,您可以在模型中创build一个setter函数:

 var MyModel = Backbone.Model.extend({ defaults: { obj1 : { "myAttribute1" : false, "myAttribute2" : true, } }, setObj1Attribute: function(name, value) { var obj1 = this.get('obj1'); obj1[name] = value; this.set('obj1', obj1); } }) 

如果您与后端进行交互,需要嵌套结构的对象。 但是骨干更容易与线性结构一起工作。

backbone.linear可以帮助你。