是否可以在Backbone.Model的initialize方法中删除属性,并将它们更改为模型的属性?

时间:2011-08-29 22:25:41

标签: javascript backbone.js

我的三个模型之间有以下对象关系(我使用Backbone-relational ...这只是描述我的数据的底层结构):

Person has many Cars
Car has many Appraisals.

我有一个方法来检索一个人,这个方法带来了所有汽车和那些汽车的评估。它看起来像这样:

{id: 1,
 name: John Doe,
 cars: [
        {id: 3, make: 'Porsche',
         appraisals: [
                        {id: 27, amount: '45000', date: '01/01/2011'}
                     ]
        },

        {id: 4, make: 'Buick', appraisals: []}
  ]
}

当我创建一个新人时,我会传递这个混乱。在我的Person的initialize函数中,我这样做:

...
initialize: function() {
  //Cars => Collection of Car
  this.cars = new Cars();
  _.each(this.get('cars'), function(car) {
    this.cars.add(new Car(car));
  });
  this.unset('cars');
}
...

在我的Car initialize函数中,我做了类似的事情:

...
initialize: function() {
  //Appraisals => Collection of Appraisal
  this.appraisals = new Appraisals();
  _.each(this.get('appraisals'), function(appraisal) {
    this.appraisals.add(new Appraisal(appraisal));
  });
  this.unset('appraisals');
}
...

我还必须覆盖Person和Car模型的toJSON函数。

这有什么问题吗?我已经看到它在其他地方建议制作嵌套集合属性而不是属性,我的经验证实这更容易,但我想知道我是在打破一些规则还是做一些愚蠢的事情。

5 个答案:

答案 0 :(得分:4)

我没有“将嵌套集合存储为属性或属性”的答案,但我认为您可以简化代码初始化嵌套集合,如下所示:

人:

...
initialize: function() {
  this.cars = new Cars(this.get('cars'));
  this.unset('cars');
}
...

汽车:

...
initialize: function() {
  this.appraisals = new Appraisals(this.get('appraisals'));
  this.unset('appraisals');
}
...

答案 1 :(得分:3)

我在这里回答了类似的问题:backbone.js - getting extra data along with the request

在我提供的答案中,更多的是关于拥有模型关联的集合 - 基本上有一个。

我认为一个人应该有一个包含汽车模型的CarsList。汽车应该有一个包含评估模型的AppraisalsList。您可能会根据需要覆盖Person和Car的parse和toJSON函数。

我肯定会避免使用关联属性。上面例子中未设置的功能给我带来了难闻的气味。

答案 2 :(得分:1)

如果我可以给出2美分的投入:

如果您要绘制类的OOD类图并使用您选择的任何面向对象语言(除了javascript之外)对关联建模,您将如何做?

你看到backbone.js有助于将'结构'放到你的javascript中,这可能会成为纠结的意大利面条代码。因此,如果你的人有很多汽车,而汽车有很多评估你有两个选择:组合与协会

组成:您在上面做的事情:人物对象负责创建汽车和汽车对象以创建评估。每个对象的“生命周期”取决于父对象。现在可能/可能不是它应该如何建模,但这是你做出的选择。

现在,让我们看看简单的关联。您可以独立创建人员,汽车和评估(如果没有汽车,可能不会存在评估,但现在让我们假设其他情况)。

现在创建了这些对象,但是你需要“连接”这些关联 - 你可以在一个单独的“初始化器”类/容器中进行外部操作,可以这么说,只需使用setter / getters即可连接它们。

结论:使用最适合您的域的模型,不要让它受数据存储(即本例中的JSON对象)的约束。 Backbone的纯粹之美来自于这种能力,可以在编码时为您的代码赋予经典的OO结构并以这种方式思考。因此,选择OO关系(组合,聚合或简单关联)的良好组合,并为您的问题选择“最佳模型”并相应地实施。

结合@ kulesa的建议,您将“清理”您的代码并实现您想要的目标,而无需担心在有效组织代码时违反任何原则/做法。

希望这有帮助!

答案 3 :(得分:1)

我个人认为使用属性来存储某些模型的数据是不合理的。你有什么经历使得属性变得更容易?

Backbone在内部似乎只对元数据使用属性(例如集合中模型的by-id和by-cid映射)并快速访问属性(例如id属性,该属性已更新每当id属性发生变化时)。使用属性也会阻止您使用Backbone的事件系统或.get() / .set(),并强制您覆盖.toJSON()

坚持使用属性,我相信你可以通过覆盖.set()来获得相同的结果 - 在.initialize()之前创建模型的新实例时会调用它,并且它也会被调用如果其他东西试图设置任何属性。我曾经做过类似的事情:

var Person = Backbone.Model.extend({
    set: function(attributes, options){
        var outAttributes = {};
        _.each(attributes, function(value, name){
            switch(name){
            case 'cars':
                outAttributes.cars = new Cars(value);
                break;
            default:
                outAttributes[name] = value;
            }
        }, this);
        Backbone.Model.prototype.set.call(this, outAttributes, options);
    }
});

...您可以将其修改为更新现有的Cars实例,而不是创建新实例。

.set()也是Backbone更新id属性值的地方,因此如果您选择使用属性而不是属性,那么吸入值可能仍然是最好的(而不是{ {1}})。

答案 4 :(得分:0)

我有类似的情况,我这样解决了:

parse: function(data) {
    if (data.Success) {
        var policies = Rens.get('Policies').model, // model with nested collextion
            claims = Rens.get('Claims').model; // model with nested collextion

        // reseting collections
        claims.claims.reset(); 
        policies.policies.reset();

        $(data.Result.Policies).each(function(i, policy) {
            var claimsList = policy.ClaimsList,
                policyWithClaims = _.clone(policy);

            claims.claims.add(claimsList);
            _.extend(policyWithClaims, {
                ClaimsList: claims.getPolicyClaims.bind({
                    context: claims,
                    policyNumber: policy.PolicyNumber
                }),
                CarYearString: Rens.formatDate(policy.CarYear).date.HH,
                PolicyEndDateString: Rens.formatDate(policy.PolicyEndDate).fullDate
            });
            policies.policies.add(policyWithClaims);
        });
    }
}

在此之后,我收集了策略,每个策略都具有链接到声明集合的方法的属性。 claims.getPolicyClaims会返回当前政策的所有声明