4

我知道这是 javascript 本身的问题(或行为),而不是 Backbone 的扩展方法,但我想知道避免它的最佳策略是什么。

让我们更好地把它放在代码中:

var MyModel = Backbone.Model.extend({
  value: 0,
  values: []
});

var myFirstModel = new MyModel();

myFirstModel.value // 0, as expected
myFirstModel.values // [], as expected

var mySecondModel = new MyModel();

mySecondModel.value = 2;
mySecondModel.values.push(2)

mySecondModel.value // 2, as expected
mySecondModel.values // [2], as expected

myFirstModel.value // 0, as expected
myFirstModel.values // [2], ... WAT!!!

我确实知道问题是我没有为 mySecondModel.values 分配新值我只是在原型中的 values 变量上进行操作,即 MyModel.prototype.values (与任何其他对象相同的问题,课程)

但这很容易搞砸。最直观的事情是将它们视为实例变量,而不是每个实例共有的变量(基于类的语言中的静态或类变量)。

到目前为止,我发现的一般解决方案是在初始化方法中初始化每个变量,如下所示:

var MyModel = Backbone.Model.extend({
  initialize: function() {
    this.value = 0;
    this.values = [];
  }
});

这样,一切都按预期工作,即使对于一个简单的值(比如 this.value)来说它不是必需的,我发现在每种情况下都坚持这个原则要容易得多。

我想知道这个问题是否有更好(更优雅,更清晰)的解决方案

4

3 回答 3

2

Array这是 JavaScript 的原型继承和对象是引用类型这一事实的影响。您传递给的对象的键/值对extend被复制到 的原型中MyModel,因此它们将由 的所有实例共享MyModel。因为values是一个数组,所以当你修改它时,你修改了每个实例的数组。

你在values里面设置的东西initialize叫做shadowing the prototype,这是解决这个问题的正确方法。

也就是说,在 的情况下Backbone.Model,如果您尝试处理模型的属性,则可以使用该defaults函数提供如下默认值:

var MyModel = Backbone.Model.extend({
  defaults: function() {
    return {
      value: 0,
      values: []
    }
  }
});

同样,这仅适用于实例的属性。

var inst = new MyModel();

// The defaults will be created for each new model,
// so this will always return a new array.
var values = inst.get('values');

对于您正在做的事情,在模型本身上指定属性的位置,您可以在 内部设置默认值initialize,就像您所做的那样。

于 2013-02-19T05:45:38.723 回答
2

您是否故意不设置valuevalues作为主干属性?如果您在实例上设置属性,而不是将它们放在扩展的主干模型定义中,它可能会按照您的预期工作。

var MyModel = Backbone.Model.extend();

var myFirstModel = new MyModel({
  value: 0,
  values: []
});

console.log(myFirstModel.get('value');  // 0
console.log(myFirstModel.get('values'); // []

var mySecondModel = new MyModel({
  value: 2,
  values: [2]
});

//mySecondModel.value = 2;
//mySecondModel.values.push(2)

console.log(mySecondModel.get('value');  // 2
console.log(mySecondModel.get('values'); // [2]

console.log(myFirstModel.get('value');   // 0
console.log(myFirstModel.get('values');  // []

jsFiddle,检查控制台日志。

于 2013-02-19T05:49:20.300 回答
1

前段时间我也偶然发现了这个问题,并通过在模型中定义默认方法来解决它。

var MyModel = Backbone.Model.extend({
  defaults: function() {
    return {
      value: 0,
      values: []
    }
  }
});
于 2013-02-19T05:47:33.457 回答