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

IT技术 javascript backbone.js backbone-model
2021-02-24 16:20:40

我有一个关于 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;

但这是好的做法吗?

6个回答

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

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

但是,如果您这样做,您将无法获得 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());
    }
});

然后访问代码将是

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

但更重要的是设置代码是

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

这将触发适当的更改事件等。这里的工作示例:http : //jsfiddle.net/g3U7j/

我没有检查backbone.js 代码,但从我的测试来看,如果你有一个嵌套的自定义模型并使用 set() 更改它的属性,它的父模型本身不会触发“更改”事件;我不得不自己触发事件。我真的应该检查代码,但这也是你的理解吗?
2021-04-20 16:20:40
@tom 说得对。当模型的属性是 的实例时Backbone.ModelBackbone 并不是特例,然后开始进行神奇的事件冒泡。
2021-05-04 16:20:40
@ChristianNunciato、pagewil、Benno:您似乎忽略了这篇文章的重点,即在 Backbone 模型中嵌套 Backbone 模型。不要在 Backbone 模型中嵌套普通对象。这里的工作示例:jsfiddle.net/g3U7j
2021-05-06 16:20:40
对于这个答案,我要补充一个建议​​,即该解决方案在广泛违反迪米特法则的情况下摇摇欲坠。我会考虑添加隐藏嵌套对象导航的便捷方法。基本上,您的调用者不需要知道模型的内部结构;毕竟,它可能会改变,调用者也不应该更聪明。
2021-05-10 16:20:40
无法让这对我有用。抛出错误:Uncaught TypeError: Object #<Object> has no method 'set'
2021-05-17 16:20:40

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

model.bind('change:user.name.first', function(){...});
model.set({'user.name.first': 'Eric'});
model.get('user.name.first'); //Eric
是的,如果您查看API,则有一个示例,例如//You can use index notation to fetch from arrays console.log(model.get('otherSpies.0.name')) //'Lana'
2021-04-21 16:20:40
效果很好!但是您示例中的第 2 行是否需要冒号而不是逗号?
2021-05-18 16:20:40

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

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

有关完整说明,请参阅 c3rin 的回答 @ https://stackoverflow.com/a/6364480/1072653

提问者应将此标记为已接受的答案。Domenic 是一个很好的开始,但这解决了它的一个问题。
2021-04-26 16:20:40
对于未来的读者,我的答案已更新,以纳入 Rusty 的最佳答案。
2021-05-16 16:20:40

我使用这种方法。

如果您有这样的 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}}

触发“更改”事件。

你确定吗?这对我不起作用。meta2= m.get('x'); meta2.id=110; m.set('x', meta2). 这不会为我触发任何更改事件:(
2021-04-20 16:20:40
感谢@HungryCoder,它在克隆时也对我有用。Backbone 必须将您所在setting的对象与您getting在设定时间所在的对象进行比较所以如果你不克隆这两个对象,那么被比较的两个对象在设定的时间是完全相同的。
2021-04-25 16:20:40
当我克隆像_.clone(m.get('x')). 谢谢
2021-05-02 16:20:40
请记住,对象通过引用传递并且是可变的,这与字符串和数字原语不同。Backbone 的 set 和构造函数方法尝试对作为参数传递的任何对象引用进行浅层克隆。不会克隆该对象属性中对其他对象的任何引用。当您设置并检索它时,引用是相同的,这意味着您可以在不触发更改的情况下改变模型。
2021-05-20 16:20:40

有一种没有人想到的解决方案,它有很多用途。您确实无法直接设置嵌套属性,除非您使用您可能不想要的第三方库。但是,您可以做的是复制原始字典,在那里设置嵌套属性,然后设置整个字典。小菜一碟。

//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