4

これはBackboneのextendメソッドではなく、JavaScript自体の問題(または動作)であることは理解していますが、それを回避するための最良の戦略は何かを知りたい.

コードに入れましょう:

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 に新しい値を割り当てていないことだと理解しています。プロトタイプにある値の変数、つまり MyModel.prototype.values を操作しているだけです (他のオブジェクトと同じ問題です。コース)

しかし、それを台無しにするのは非常に簡単です。最も直感的なことは、それらをインスタンス変数として考えることであり、すべてのインスタンスに共通の変数 (クラスベース言語の静的変数またはクラス変数) ではありません。

これまでのところ、私が見つけた一般的な解決策は、次のように、初期化メソッドですべての変数を初期化することです。

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

そうすれば、すべてが期待どおりに機能し、単純な値 (this.value など) には必要ありませんが、すべての場合にこの原則に固執する方がずっと簡単だと思います。

この問題に対するより良い(よりエレガントで明確な)解決策があるかどうか疑問に思っています

4

3 に答える 3

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あなた次第です。

于 2013-02-19T05:45:38.723 に答える
2

バックボーン属性として意図的valueに andを設定していませんか? 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、コンソール ログを確認します。

于 2013-02-19T05:49:20.300 に答える
1

私も以前この問題に出くわし、モデルにデフォルトメソッドを定義することで解決しました。

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