1. ホーム
  2. javascript

[解決済み】オブジェクトリテラルとして宣言されたノックアウトビューモデルと関数の違いについて

2022-04-16 08:27:14

質問

Knockout jsでは、View Modelsはどちらかで宣言されていますね。

var viewModel = {
    firstname: ko.observable("Bob")
};

ko.applyBindings(viewModel );

または

var viewModel = function() {
    this.firstname= ko.observable("Bob");
};

ko.applyBindings(new viewModel ());

両者の違いがあるとすれば、それは何でしょうか?

確かに この議論 をノックアウトjsのgoogleグループに投稿しましたが、満足のいく回答は得られませんでした。

例えば、あるデータでモデルを初期化したい場合、その理由はわかります。

var viewModel = function(person) {
    this.firstname= ko.observable(person.firstname);
};

var person = ... ;
ko.applyBindings(new viewModel(person));

でも、そうでないなら、どのスタイルを選んでもいいのでしょうか?

どのように解決するのですか?

ビューモデルを定義するために関数を使用することには、いくつかの利点があります。

の値にすぐにアクセスできることが主な利点です。 this は、作成されるインスタンスに等しい。 つまり、以下のようなことができます。

var ViewModel = function(first, last) {
  this.first = ko.observable(first);
  this.last = ko.observable(last);
  this.full = ko.computed(function() {
     return this.first() + " " + this.last();
  }, this);
};

つまり、計算された観測値は this 別のスコープから呼び出されたとしても、です。

オブジェクト・リテラルだと、そうせざるを得ない。

var viewModel = {
   first: ko.observable("Bob"),
   last: ko.observable("Smith"),
};

viewModel.full = ko.computed(function() {
   return this.first() + " " + this.last();
}, viewModel);

その場合は viewModel は計算されたobservableの中で直接評価されますが、(デフォルトでは)すぐに評価されるので、オブジェクトリテラルの中で定義することはできません。 viewModel は、オブジェクト・リテラルを閉じた後でないと定義されません。 多くの人は、ビューモデルの作成が1回の呼び出しでカプセル化されないことを嫌がります。

もう一つのパターンとして this が常に適切な値になるように、関数内の変数に this を作成し、それを代わりに使用します。 これは、次のようなものです。

var ViewModel = function() {
    var self = this;
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         self.items.remove(item);
    }
};

さて、個々のアイテムのスコープで、以下のように呼び出したとします。 $root.removeItem の値は this は、実際にはそのレベルでバインドされているデータ (これはアイテムになります) になります。 この場合、self を使用することで、ビューモデル全体から削除されていることを確認することができます。

もう一つの方法は bind は、モダンブラウザでサポートされており、サポートされていない場合は、KOによって追加されます。 その場合、次のようになります。

var ViewModel = function() {
    this.items = ko.observableArray();
    this.removeItem = function(item) {
         this.items.remove(item);
    }.bind(this);
};

このトピックにはもっと多くのことが語られ、多くのパターン(moduleパターンやexparing moduleパターンなど)がありますが、基本的に関数を使用すると、オブジェクトの生成方法をより柔軟に制御でき、インスタンスのプライベート変数を参照することが可能になります。