我知道这是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(同样的)当然,任何其他对象的问题)
但是这很容易搞砸。最直观的是将它们视为INSTANCE变量,而不是每个实例共有的变量(基于类的语言中的静态或类变量)。
到目前为止,我发现的一般解决方案是初始化initialize方法中的每个变量,如下所示:
var MyModel = Backbone.Model.extend({
initialize: function() {
this.value = 0;
this.values = [];
}
});
这样一切都按预期工作,即使它不是一个简单值(如this.value)的必要条件,我发现在每种情况下都坚持这个原则要容易得多。
我想知道这个问题是否有更好(更优雅,更清晰)的解决方案
答案 0 :(得分:2)
这是JavaScript的原型继承的效果,以及Array
对象是引用类型的事实。您传递给extend
的对象的键/值对将复制到MyModel
的原型中,因此MyModel
的所有实例都会共享它们。因为values
是一个数组,所以在修改它时,可以为每个实例修改数组。
您在values
内设置initialize
所做的工作称为阴影原型,这是解决此问题的正确方法。
那就是说,在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
内的默认值,就像您所做的那样。
答案 1 :(得分:2)
您是否故意不将value
和values
设置为主干属性?如果在实例上设置属性,而不是将它们放在扩展主干模型定义中,它可能会按预期工作。
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,检查控制台日志。
答案 2 :(得分:1)
我也曾经偶然发现这个问题并通过在模型中定义defaults方法解决了这个问题。
var MyModel = Backbone.Model.extend({
defaults: function() {
return {
value: 0,
values: []
}
}
});