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

for*_*ice 105 javascript backbone.js backbone-model

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

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

另一个问题:

2)在Model中,除了defaults对象之外,我可以/应该在哪里声明我的模型的其他属性,以便可以通过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?
    }
});
Run Code Online (Sandbox Code Playgroud)

我知道我能做到:

this.model.get("obj1").myAttribute1;
Run Code Online (Sandbox Code Playgroud)

但这是好的做法吗?

Dom*_*nic 144

虽然this.model.get("obj1").myAttribute1很好,但它有点问题,因为那时你可能会想要为set做同样类型的事情,即

this.model.get("obj1").myAttribute1 = true;
Run Code Online (Sandbox Code Playgroud)

但是如果你这样做,你将无法获得Backbone模型的好处myAttribute1,比如更改事件或验证.

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

var Obj = Backbone.Model.extend({
    defaults: {
        myAttribute1: false,
        myAttribute2: true
    }
});

var MyModel = Backbone.Model.extend({
    initialize: function () {
        this.set("obj1", new Obj());
    }
});
Run Code Online (Sandbox Code Playgroud)

然后访问代码将是

var x = this.model.get("obj1").get("myAttribute1");
Run Code Online (Sandbox Code Playgroud)

但更重要的是设置代码

this.model.get("obj1").set({ myAttribute1: true });
Run Code Online (Sandbox Code Playgroud)

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

  • 对于这个答案,我想补充说明这个解决方案在广泛的Demeter违规法中徘徊.我会考虑添加隐藏导航到嵌套对象的便捷方法.基本上,您的呼叫者不需要知道模型的内部结构; 毕竟,它可能会改变,呼叫者应该更聪明. (23认同)
  • 不能让这个为我工作.引发错误:`未捕获TypeError:对象#<Object>没有方法'set' (7认同)
  • @tom是正确的.当模型的属性是`Backbone.Model`的实例,然后开始进行魔法事件冒泡时,Backbone不是特殊情况. (2认同)

evi*_*ery 74

我为此创建了骨干深度模型 - 只需扩展Backbone.DeepModel而不是Backbone.Model,然后您可以使用路径来获取/设置嵌套模型属性.它也维护变化事件.

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

  • 我喜欢这种方法,想知道为什么它不包含在Backbone中是默认的... (16认同)

小智 16

Domenic的解决方案将起作用,但每个新的MyModel将指向相同的Obj实例.为避免这种情况,MyModel应如下所示:

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

有关完整说明,请参阅c3rin的答案@ /sf/answers/445513631/.

  • Asker应该将此标记为已接受的答案.Domenic是一个很好的开始,但这解决了它的问题. (2认同)

Nat*_*non 5

我用这种方法.

如果您有这样的Backbone模型:

var nestedAttrModel = new Backbone.Model({
    a: {b: 1, c: 2}
});
Run Code Online (Sandbox Code Playgroud)

您可以使用以下项设置属性"ab":

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

现在您的模型将具有以下属性:

{a: {b: 3, c: 2}}
Run Code Online (Sandbox Code Playgroud)

随着"改变"事件被解雇.